blob: 9fd8c02822b3fc078b3f7f10be00b1528d3a9288 [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
7import sys
8import textwrap
9import tempfile
10import unittest
11import argparse
12
Benjamin Peterson0e717ad2010-03-02 23:02:02 +000013from StringIO import StringIO
14
Michael Foord91a2c892010-04-08 00:04:24 +000015class StdIOBuffer(StringIO):
16 pass
17
Benjamin Peterson036fae32010-03-02 22:20:10 +000018from test import test_support
19
Benjamin Petersona39e9662010-03-02 22:05:59 +000020class TestCase(unittest.TestCase):
21
22 def assertEqual(self, obj1, obj2):
23 if obj1 != obj2:
24 print('')
25 print(repr(obj1))
26 print(repr(obj2))
27 print(obj1)
28 print(obj2)
29 super(TestCase, self).assertEqual(obj1, obj2)
30
Steven Bethardabacccc2010-11-01 14:09:21 +000031 def setUp(self):
32 # The tests assume that line wrapping occurs at 80 columns, but this
33 # behaviour can be overridden by setting the COLUMNS environment
34 # variable. To ensure that this assumption is true, unset COLUMNS.
35 env = test_support.EnvironmentVarGuard()
36 env.unset("COLUMNS")
37 self.addCleanup(env.__exit__)
Benjamin Petersona39e9662010-03-02 22:05:59 +000038
Michael Foord91a2c892010-04-08 00:04:24 +000039
Benjamin Petersona39e9662010-03-02 22:05:59 +000040class TempDirMixin(object):
41
42 def setUp(self):
43 self.temp_dir = tempfile.mkdtemp()
44 self.old_dir = os.getcwd()
45 os.chdir(self.temp_dir)
46
47 def tearDown(self):
48 os.chdir(self.old_dir)
49 while True:
50 try:
51 shutil.rmtree(self.temp_dir)
52 except WindowsError:
53 continue
54 else:
55 break
56
57
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'])),
1377 ]
1378
1379
1380class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1381 """Test reading arguments from a file"""
1382
1383 def setUp(self):
1384 super(TestArgumentsFromFileConverter, self).setUp()
1385 file_texts = [
1386 ('hello', 'hello world!\n'),
1387 ]
1388 for path, text in file_texts:
1389 file = open(path, 'w')
1390 file.write(text)
1391 file.close()
1392
1393 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1394
1395 def convert_arg_line_to_args(self, arg_line):
1396 for arg in arg_line.split():
1397 if not arg.strip():
1398 continue
1399 yield arg
1400 parser_class = FromFileConverterArgumentParser
1401 parser_signature = Sig(fromfile_prefix_chars='@')
1402 argument_signatures = [
1403 Sig('y', nargs='+'),
1404 ]
1405 failures = []
1406 successes = [
1407 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1408 ]
1409
1410
1411# =====================
1412# Type conversion tests
1413# =====================
1414
1415class TestFileTypeRepr(TestCase):
1416
1417 def test_r(self):
1418 type = argparse.FileType('r')
1419 self.assertEqual("FileType('r')", repr(type))
1420
1421 def test_wb_1(self):
1422 type = argparse.FileType('wb', 1)
1423 self.assertEqual("FileType('wb', 1)", repr(type))
1424
1425
1426class RFile(object):
1427 seen = {}
1428
1429 def __init__(self, name):
1430 self.name = name
1431
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001432 __hash__ = None
1433
Benjamin Petersona39e9662010-03-02 22:05:59 +00001434 def __eq__(self, other):
1435 if other in self.seen:
1436 text = self.seen[other]
1437 else:
1438 text = self.seen[other] = other.read()
1439 other.close()
1440 if not isinstance(text, str):
1441 text = text.decode('ascii')
1442 return self.name == other.name == text
1443
1444
1445class TestFileTypeR(TempDirMixin, ParserTestCase):
1446 """Test the FileType option/argument type for reading files"""
1447
1448 def setUp(self):
1449 super(TestFileTypeR, self).setUp()
1450 for file_name in ['foo', 'bar']:
1451 file = open(os.path.join(self.temp_dir, file_name), 'w')
1452 file.write(file_name)
1453 file.close()
1454
1455 argument_signatures = [
1456 Sig('-x', type=argparse.FileType()),
1457 Sig('spam', type=argparse.FileType('r')),
1458 ]
1459 failures = ['-x', '-x bar']
1460 successes = [
1461 ('foo', NS(x=None, spam=RFile('foo'))),
1462 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1463 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1464 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
1465 ]
1466
1467
1468class TestFileTypeRB(TempDirMixin, ParserTestCase):
1469 """Test the FileType option/argument type for reading files"""
1470
1471 def setUp(self):
1472 super(TestFileTypeRB, self).setUp()
1473 for file_name in ['foo', 'bar']:
1474 file = open(os.path.join(self.temp_dir, file_name), 'w')
1475 file.write(file_name)
1476 file.close()
1477
1478 argument_signatures = [
1479 Sig('-x', type=argparse.FileType('rb')),
1480 Sig('spam', type=argparse.FileType('rb')),
1481 ]
1482 failures = ['-x', '-x bar']
1483 successes = [
1484 ('foo', NS(x=None, spam=RFile('foo'))),
1485 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1486 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
1487 ('-x - -', NS(x=sys.stdin, spam=sys.stdin)),
1488 ]
1489
1490
1491class WFile(object):
1492 seen = set()
1493
1494 def __init__(self, name):
1495 self.name = name
1496
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001497 __hash__ = None
1498
Benjamin Petersona39e9662010-03-02 22:05:59 +00001499 def __eq__(self, other):
1500 if other not in self.seen:
1501 text = 'Check that file is writable.'
1502 if 'b' in other.mode:
1503 text = text.encode('ascii')
1504 other.write(text)
1505 other.close()
1506 self.seen.add(other)
1507 return self.name == other.name
1508
1509
1510class TestFileTypeW(TempDirMixin, ParserTestCase):
1511 """Test the FileType option/argument type for writing files"""
1512
1513 argument_signatures = [
1514 Sig('-x', type=argparse.FileType('w')),
1515 Sig('spam', type=argparse.FileType('w')),
1516 ]
1517 failures = ['-x', '-x bar']
1518 successes = [
1519 ('foo', NS(x=None, spam=WFile('foo'))),
1520 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1521 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1522 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1523 ]
1524
1525
1526class TestFileTypeWB(TempDirMixin, ParserTestCase):
1527
1528 argument_signatures = [
1529 Sig('-x', type=argparse.FileType('wb')),
1530 Sig('spam', type=argparse.FileType('wb')),
1531 ]
1532 failures = ['-x', '-x bar']
1533 successes = [
1534 ('foo', NS(x=None, spam=WFile('foo'))),
1535 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1536 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
1537 ('-x - -', NS(x=sys.stdout, spam=sys.stdout)),
1538 ]
1539
1540
1541class TestTypeCallable(ParserTestCase):
1542 """Test some callables as option/argument types"""
1543
1544 argument_signatures = [
1545 Sig('--eggs', type=complex),
1546 Sig('spam', type=float),
1547 ]
1548 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1549 successes = [
1550 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1551 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1552 ('1024.675', NS(eggs=None, spam=1024.675)),
1553 ]
1554
1555
1556class TestTypeUserDefined(ParserTestCase):
1557 """Test a user-defined option/argument type"""
1558
1559 class MyType(TestCase):
1560
1561 def __init__(self, value):
1562 self.value = value
1563
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001564 __hash__ = None
1565
Benjamin Petersona39e9662010-03-02 22:05:59 +00001566 def __eq__(self, other):
1567 return (type(self), self.value) == (type(other), other.value)
1568
1569 argument_signatures = [
1570 Sig('-x', type=MyType),
1571 Sig('spam', type=MyType),
1572 ]
1573 failures = []
1574 successes = [
1575 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1576 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1577 ]
1578
1579
1580class TestTypeClassicClass(ParserTestCase):
1581 """Test a classic class type"""
1582
1583 class C:
1584
1585 def __init__(self, value):
1586 self.value = value
1587
Benjamin Peterson6b31fd02010-03-07 00:29:44 +00001588 __hash__ = None
1589
Benjamin Petersona39e9662010-03-02 22:05:59 +00001590 def __eq__(self, other):
1591 return (type(self), self.value) == (type(other), other.value)
1592
1593 argument_signatures = [
1594 Sig('-x', type=C),
1595 Sig('spam', type=C),
1596 ]
1597 failures = []
1598 successes = [
1599 ('a -x b', NS(x=C('b'), spam=C('a'))),
1600 ('-xf g', NS(x=C('f'), spam=C('g'))),
1601 ]
1602
1603
1604class TestTypeRegistration(TestCase):
1605 """Test a user-defined type by registering it"""
1606
1607 def test(self):
1608
1609 def get_my_type(string):
1610 return 'my_type{%s}' % string
1611
1612 parser = argparse.ArgumentParser()
1613 parser.register('type', 'my_type', get_my_type)
1614 parser.add_argument('-x', type='my_type')
1615 parser.add_argument('y', type='my_type')
1616
1617 self.assertEqual(parser.parse_args('1'.split()),
1618 NS(x=None, y='my_type{1}'))
1619 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1620 NS(x='my_type{1}', y='my_type{42}'))
1621
1622
1623# ============
1624# Action tests
1625# ============
1626
1627class TestActionUserDefined(ParserTestCase):
1628 """Test a user-defined option/argument action"""
1629
1630 class OptionalAction(argparse.Action):
1631
1632 def __call__(self, parser, namespace, value, option_string=None):
1633 try:
1634 # check destination and option string
1635 assert self.dest == 'spam', 'dest: %s' % self.dest
1636 assert option_string == '-s', 'flag: %s' % option_string
1637 # when option is before argument, badger=2, and when
1638 # option is after argument, badger=<whatever was set>
1639 expected_ns = NS(spam=0.25)
1640 if value in [0.125, 0.625]:
1641 expected_ns.badger = 2
1642 elif value in [2.0]:
1643 expected_ns.badger = 84
1644 else:
1645 raise AssertionError('value: %s' % value)
1646 assert expected_ns == namespace, ('expected %s, got %s' %
1647 (expected_ns, namespace))
1648 except AssertionError:
1649 e = sys.exc_info()[1]
1650 raise ArgumentParserError('opt_action failed: %s' % e)
1651 setattr(namespace, 'spam', value)
1652
1653 class PositionalAction(argparse.Action):
1654
1655 def __call__(self, parser, namespace, value, option_string=None):
1656 try:
1657 assert option_string is None, ('option_string: %s' %
1658 option_string)
1659 # check destination
1660 assert self.dest == 'badger', 'dest: %s' % self.dest
1661 # when argument is before option, spam=0.25, and when
1662 # option is after argument, spam=<whatever was set>
1663 expected_ns = NS(badger=2)
1664 if value in [42, 84]:
1665 expected_ns.spam = 0.25
1666 elif value in [1]:
1667 expected_ns.spam = 0.625
1668 elif value in [2]:
1669 expected_ns.spam = 0.125
1670 else:
1671 raise AssertionError('value: %s' % value)
1672 assert expected_ns == namespace, ('expected %s, got %s' %
1673 (expected_ns, namespace))
1674 except AssertionError:
1675 e = sys.exc_info()[1]
1676 raise ArgumentParserError('arg_action failed: %s' % e)
1677 setattr(namespace, 'badger', value)
1678
1679 argument_signatures = [
1680 Sig('-s', dest='spam', action=OptionalAction,
1681 type=float, default=0.25),
1682 Sig('badger', action=PositionalAction,
1683 type=int, nargs='?', default=2),
1684 ]
1685 failures = []
1686 successes = [
1687 ('-s0.125', NS(spam=0.125, badger=2)),
1688 ('42', NS(spam=0.25, badger=42)),
1689 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1690 ('84 -s2', NS(spam=2.0, badger=84)),
1691 ]
1692
1693
1694class TestActionRegistration(TestCase):
1695 """Test a user-defined action supplied by registering it"""
1696
1697 class MyAction(argparse.Action):
1698
1699 def __call__(self, parser, namespace, values, option_string=None):
1700 setattr(namespace, self.dest, 'foo[%s]' % values)
1701
1702 def test(self):
1703
1704 parser = argparse.ArgumentParser()
1705 parser.register('action', 'my_action', self.MyAction)
1706 parser.add_argument('badger', action='my_action')
1707
1708 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1709 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1710
1711
1712# ================
1713# Subparsers tests
1714# ================
1715
1716class TestAddSubparsers(TestCase):
1717 """Test the add_subparsers method"""
1718
1719 def assertArgumentParserError(self, *args, **kwargs):
1720 self.assertRaises(ArgumentParserError, *args, **kwargs)
1721
R. David Murray1cbf78e2010-08-03 18:14:01 +00001722 def _get_parser(self, subparser_help=False, prefix_chars=None):
Benjamin Petersona39e9662010-03-02 22:05:59 +00001723 # create a parser with a subparsers argument
R. David Murray1cbf78e2010-08-03 18:14:01 +00001724 if prefix_chars:
1725 parser = ErrorRaisingArgumentParser(
1726 prog='PROG', description='main description', prefix_chars=prefix_chars)
1727 parser.add_argument(
1728 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1729 else:
1730 parser = ErrorRaisingArgumentParser(
1731 prog='PROG', description='main description')
1732 parser.add_argument(
1733 '--foo', action='store_true', help='foo help')
Benjamin Petersona39e9662010-03-02 22:05:59 +00001734 parser.add_argument(
1735 'bar', type=float, help='bar help')
1736
1737 # check that only one subparsers argument can be added
1738 subparsers = parser.add_subparsers(help='command help')
1739 self.assertArgumentParserError(parser.add_subparsers)
1740
1741 # add first sub-parser
1742 parser1_kwargs = dict(description='1 description')
1743 if subparser_help:
1744 parser1_kwargs['help'] = '1 help'
1745 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1746 parser1.add_argument('-w', type=int, help='w help')
1747 parser1.add_argument('x', choices='abc', help='x help')
1748
1749 # add second sub-parser
1750 parser2_kwargs = dict(description='2 description')
1751 if subparser_help:
1752 parser2_kwargs['help'] = '2 help'
1753 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1754 parser2.add_argument('-y', choices='123', help='y help')
1755 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1756
1757 # return the main parser
1758 return parser
1759
1760 def setUp(self):
Steven Bethardabacccc2010-11-01 14:09:21 +00001761 super(TestAddSubparsers, self).setUp()
Benjamin Petersona39e9662010-03-02 22:05:59 +00001762 self.parser = self._get_parser()
1763 self.command_help_parser = self._get_parser(subparser_help=True)
1764
1765 def test_parse_args_failures(self):
1766 # check some failure cases:
1767 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1768 '0.5 1 -y', '0.5 2 -w']:
1769 args = args_str.split()
1770 self.assertArgumentParserError(self.parser.parse_args, args)
1771
1772 def test_parse_args(self):
1773 # check some non-failure cases:
1774 self.assertEqual(
1775 self.parser.parse_args('0.5 1 b -w 7'.split()),
1776 NS(foo=False, bar=0.5, w=7, x='b'),
1777 )
1778 self.assertEqual(
1779 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1780 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1781 )
1782 self.assertEqual(
1783 self.parser.parse_args('--foo 0.125 1 c'.split()),
1784 NS(foo=True, bar=0.125, w=None, x='c'),
1785 )
1786
1787 def test_dest(self):
1788 parser = ErrorRaisingArgumentParser()
1789 parser.add_argument('--foo', action='store_true')
1790 subparsers = parser.add_subparsers(dest='bar')
1791 parser1 = subparsers.add_parser('1')
1792 parser1.add_argument('baz')
1793 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1794 parser.parse_args('1 2'.split()))
1795
1796 def test_help(self):
1797 self.assertEqual(self.parser.format_usage(),
1798 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1799 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
1800 usage: PROG [-h] [--foo] bar {1,2} ...
1801
1802 main description
1803
1804 positional arguments:
1805 bar bar help
1806 {1,2} command help
1807
1808 optional arguments:
1809 -h, --help show this help message and exit
1810 --foo foo help
1811 '''))
1812
R. David Murray1cbf78e2010-08-03 18:14:01 +00001813 def test_help_extra_prefix_chars(self):
1814 # Make sure - is still used for help if it is a non-first prefix char
1815 parser = self._get_parser(prefix_chars='+:-')
1816 self.assertEqual(parser.format_usage(),
1817 'usage: PROG [-h] [++foo] bar {1,2} ...\n')
1818 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1819 usage: PROG [-h] [++foo] bar {1,2} ...
1820
1821 main description
1822
1823 positional arguments:
1824 bar bar help
1825 {1,2} command help
1826
1827 optional arguments:
1828 -h, --help show this help message and exit
1829 ++foo foo help
1830 '''))
1831
1832
1833 def test_help_alternate_prefix_chars(self):
1834 parser = self._get_parser(prefix_chars='+:/')
1835 self.assertEqual(parser.format_usage(),
1836 'usage: PROG [+h] [++foo] bar {1,2} ...\n')
1837 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1838 usage: PROG [+h] [++foo] bar {1,2} ...
1839
1840 main description
1841
1842 positional arguments:
1843 bar bar help
1844 {1,2} command help
1845
1846 optional arguments:
1847 +h, ++help show this help message and exit
1848 ++foo foo help
1849 '''))
1850
Benjamin Petersona39e9662010-03-02 22:05:59 +00001851 def test_parser_command_help(self):
1852 self.assertEqual(self.command_help_parser.format_usage(),
1853 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1854 self.assertEqual(self.command_help_parser.format_help(),
1855 textwrap.dedent('''\
1856 usage: PROG [-h] [--foo] bar {1,2} ...
1857
1858 main description
1859
1860 positional arguments:
1861 bar bar help
1862 {1,2} command help
1863 1 1 help
1864 2 2 help
1865
1866 optional arguments:
1867 -h, --help show this help message and exit
1868 --foo foo help
1869 '''))
1870
1871 def test_subparser_title_help(self):
1872 parser = ErrorRaisingArgumentParser(prog='PROG',
1873 description='main description')
1874 parser.add_argument('--foo', action='store_true', help='foo help')
1875 parser.add_argument('bar', help='bar help')
1876 subparsers = parser.add_subparsers(title='subcommands',
1877 description='command help',
1878 help='additional text')
1879 parser1 = subparsers.add_parser('1')
1880 parser2 = subparsers.add_parser('2')
1881 self.assertEqual(parser.format_usage(),
1882 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
1883 self.assertEqual(parser.format_help(), textwrap.dedent('''\
1884 usage: PROG [-h] [--foo] bar {1,2} ...
1885
1886 main description
1887
1888 positional arguments:
1889 bar bar help
1890
1891 optional arguments:
1892 -h, --help show this help message and exit
1893 --foo foo help
1894
1895 subcommands:
1896 command help
1897
1898 {1,2} additional text
1899 '''))
1900
1901 def _test_subparser_help(self, args_str, expected_help):
1902 try:
1903 self.parser.parse_args(args_str.split())
1904 except ArgumentParserError:
1905 err = sys.exc_info()[1]
1906 if err.stdout != expected_help:
1907 print(repr(expected_help))
1908 print(repr(err.stdout))
1909 self.assertEqual(err.stdout, expected_help)
1910
1911 def test_subparser1_help(self):
1912 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
1913 usage: PROG bar 1 [-h] [-w W] {a,b,c}
1914
1915 1 description
1916
1917 positional arguments:
1918 {a,b,c} x help
1919
1920 optional arguments:
1921 -h, --help show this help message and exit
1922 -w W w help
1923 '''))
1924
1925 def test_subparser2_help(self):
1926 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
1927 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
1928
1929 2 description
1930
1931 positional arguments:
1932 z z help
1933
1934 optional arguments:
1935 -h, --help show this help message and exit
1936 -y {1,2,3} y help
1937 '''))
1938
1939# ============
1940# Groups tests
1941# ============
1942
1943class TestPositionalsGroups(TestCase):
1944 """Tests that order of group positionals matches construction order"""
1945
1946 def test_nongroup_first(self):
1947 parser = ErrorRaisingArgumentParser()
1948 parser.add_argument('foo')
1949 group = parser.add_argument_group('g')
1950 group.add_argument('bar')
1951 parser.add_argument('baz')
1952 expected = NS(foo='1', bar='2', baz='3')
1953 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001954 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001955
1956 def test_group_first(self):
1957 parser = ErrorRaisingArgumentParser()
1958 group = parser.add_argument_group('xxx')
1959 group.add_argument('foo')
1960 parser.add_argument('bar')
1961 parser.add_argument('baz')
1962 expected = NS(foo='1', bar='2', baz='3')
1963 result = parser.parse_args('1 2 3'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001964 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001965
1966 def test_interleaved_groups(self):
1967 parser = ErrorRaisingArgumentParser()
1968 group = parser.add_argument_group('xxx')
1969 parser.add_argument('foo')
1970 group.add_argument('bar')
1971 parser.add_argument('baz')
1972 group = parser.add_argument_group('yyy')
1973 group.add_argument('frell')
1974 expected = NS(foo='1', bar='2', baz='3', frell='4')
1975 result = parser.parse_args('1 2 3 4'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00001976 self.assertEqual(expected, result)
Benjamin Petersona39e9662010-03-02 22:05:59 +00001977
1978# ===================
1979# Parent parser tests
1980# ===================
1981
1982class TestParentParsers(TestCase):
1983 """Tests that parsers can be created with parent parsers"""
1984
1985 def assertArgumentParserError(self, *args, **kwargs):
1986 self.assertRaises(ArgumentParserError, *args, **kwargs)
1987
1988 def setUp(self):
Steven Bethardabacccc2010-11-01 14:09:21 +00001989 super(TestParentParsers, self).setUp()
Benjamin Petersona39e9662010-03-02 22:05:59 +00001990 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
1991 self.wxyz_parent.add_argument('--w')
1992 x_group = self.wxyz_parent.add_argument_group('x')
1993 x_group.add_argument('-y')
1994 self.wxyz_parent.add_argument('z')
1995
1996 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
1997 self.abcd_parent.add_argument('a')
1998 self.abcd_parent.add_argument('-b')
1999 c_group = self.abcd_parent.add_argument_group('c')
2000 c_group.add_argument('--d')
2001
2002 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2003 self.w_parent.add_argument('--w')
2004
2005 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2006 self.z_parent.add_argument('z')
2007
2008 # parents with mutually exclusive groups
2009 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2010 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2011 group.add_argument('-a', action='store_true')
2012 group.add_argument('-b', action='store_true')
2013
Benjamin Peterson036fae32010-03-02 22:20:10 +00002014 self.main_program = os.path.basename(sys.argv[0])
2015
Benjamin Petersona39e9662010-03-02 22:05:59 +00002016 def test_single_parent(self):
2017 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2018 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2019 NS(w='3', y='1', z='2'))
2020
2021 def test_single_parent_mutex(self):
2022 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2023 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2024 self._test_mutex_ab(parser.parse_args)
2025
2026 def test_single_granparent_mutex(self):
2027 parents = [self.ab_mutex_parent]
2028 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2029 parser = ErrorRaisingArgumentParser(parents=[parser])
2030 self._test_mutex_ab(parser.parse_args)
2031
2032 def _test_mutex_ab(self, parse_args):
2033 self.assertEqual(parse_args([]), NS(a=False, b=False))
2034 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2035 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2036 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2037 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2038 self.assertArgumentParserError(parse_args, ['-c'])
2039 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2040 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2041
2042 def test_multiple_parents(self):
2043 parents = [self.abcd_parent, self.wxyz_parent]
2044 parser = ErrorRaisingArgumentParser(parents=parents)
2045 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2046 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2047
2048 def test_multiple_parents_mutex(self):
2049 parents = [self.ab_mutex_parent, self.wxyz_parent]
2050 parser = ErrorRaisingArgumentParser(parents=parents)
2051 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2052 NS(a=True, b=False, w='2', y=None, z='3'))
2053 self.assertArgumentParserError(
2054 parser.parse_args, '-a --w 2 3 -b'.split())
2055 self.assertArgumentParserError(
2056 parser.parse_args, '-a -b --w 2 3'.split())
2057
2058 def test_conflicting_parents(self):
2059 self.assertRaises(
2060 argparse.ArgumentError,
2061 argparse.ArgumentParser,
2062 parents=[self.w_parent, self.wxyz_parent])
2063
2064 def test_conflicting_parents_mutex(self):
2065 self.assertRaises(
2066 argparse.ArgumentError,
2067 argparse.ArgumentParser,
2068 parents=[self.abcd_parent, self.ab_mutex_parent])
2069
2070 def test_same_argument_name_parents(self):
2071 parents = [self.wxyz_parent, self.z_parent]
2072 parser = ErrorRaisingArgumentParser(parents=parents)
2073 self.assertEqual(parser.parse_args('1 2'.split()),
2074 NS(w=None, y=None, z='2'))
2075
2076 def test_subparser_parents(self):
2077 parser = ErrorRaisingArgumentParser()
2078 subparsers = parser.add_subparsers()
2079 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2080 abcde_parser.add_argument('e')
2081 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2082 NS(a='3', b='1', d='2', e='4'))
2083
2084 def test_subparser_parents_mutex(self):
2085 parser = ErrorRaisingArgumentParser()
2086 subparsers = parser.add_subparsers()
2087 parents = [self.ab_mutex_parent]
2088 abc_parser = subparsers.add_parser('foo', parents=parents)
2089 c_group = abc_parser.add_argument_group('c_group')
2090 c_group.add_argument('c')
2091 parents = [self.wxyz_parent, self.ab_mutex_parent]
2092 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2093 wxyzabe_parser.add_argument('e')
2094 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2095 NS(a=True, b=False, c='4'))
2096 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2097 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2098 self.assertArgumentParserError(
2099 parser.parse_args, 'foo -a -b 4'.split())
2100 self.assertArgumentParserError(
2101 parser.parse_args, 'bar -b -a 4'.split())
2102
2103 def test_parent_help(self):
2104 parents = [self.abcd_parent, self.wxyz_parent]
2105 parser = ErrorRaisingArgumentParser(parents=parents)
2106 parser_help = parser.format_help()
2107 self.assertEqual(parser_help, textwrap.dedent('''\
Benjamin Peterson036fae32010-03-02 22:20:10 +00002108 usage: {} [-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Petersona39e9662010-03-02 22:05:59 +00002109
2110 positional arguments:
2111 a
2112 z
2113
2114 optional arguments:
2115 -h, --help show this help message and exit
2116 -b B
2117 --w W
2118
2119 c:
2120 --d D
2121
2122 x:
2123 -y Y
Benjamin Peterson036fae32010-03-02 22:20:10 +00002124 '''.format(self.main_program)))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002125
2126 def test_groups_parents(self):
2127 parent = ErrorRaisingArgumentParser(add_help=False)
2128 g = parent.add_argument_group(title='g', description='gd')
2129 g.add_argument('-w')
2130 g.add_argument('-x')
2131 m = parent.add_mutually_exclusive_group()
2132 m.add_argument('-y')
2133 m.add_argument('-z')
2134 parser = ErrorRaisingArgumentParser(parents=[parent])
2135
2136 self.assertRaises(ArgumentParserError, parser.parse_args,
2137 ['-y', 'Y', '-z', 'Z'])
2138
2139 parser_help = parser.format_help()
2140 self.assertEqual(parser_help, textwrap.dedent('''\
Benjamin Peterson036fae32010-03-02 22:20:10 +00002141 usage: {} [-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Petersona39e9662010-03-02 22:05:59 +00002142
2143 optional arguments:
2144 -h, --help show this help message and exit
2145 -y Y
2146 -z Z
2147
2148 g:
2149 gd
2150
2151 -w W
2152 -x X
Benjamin Peterson036fae32010-03-02 22:20:10 +00002153 '''.format(self.main_program)))
Benjamin Petersona39e9662010-03-02 22:05:59 +00002154
2155# ==============================
2156# Mutually exclusive group tests
2157# ==============================
2158
2159class TestMutuallyExclusiveGroupErrors(TestCase):
2160
2161 def test_invalid_add_argument_group(self):
2162 parser = ErrorRaisingArgumentParser()
2163 raises = self.assertRaises
2164 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2165
2166 def test_invalid_add_argument(self):
2167 parser = ErrorRaisingArgumentParser()
2168 group = parser.add_mutually_exclusive_group()
2169 add_argument = group.add_argument
2170 raises = self.assertRaises
2171 raises(ValueError, add_argument, '--foo', required=True)
2172 raises(ValueError, add_argument, 'bar')
2173 raises(ValueError, add_argument, 'bar', nargs='+')
2174 raises(ValueError, add_argument, 'bar', nargs=1)
2175 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2176
2177
2178class MEMixin(object):
2179
2180 def test_failures_when_not_required(self):
2181 parse_args = self.get_parser(required=False).parse_args
2182 error = ArgumentParserError
2183 for args_string in self.failures:
2184 self.assertRaises(error, parse_args, args_string.split())
2185
2186 def test_failures_when_required(self):
2187 parse_args = self.get_parser(required=True).parse_args
2188 error = ArgumentParserError
2189 for args_string in self.failures + ['']:
2190 self.assertRaises(error, parse_args, args_string.split())
2191
2192 def test_successes_when_not_required(self):
2193 parse_args = self.get_parser(required=False).parse_args
2194 successes = self.successes + self.successes_when_not_required
2195 for args_string, expected_ns in successes:
2196 actual_ns = parse_args(args_string.split())
2197 self.assertEqual(actual_ns, expected_ns)
2198
2199 def test_successes_when_required(self):
2200 parse_args = self.get_parser(required=True).parse_args
2201 for args_string, expected_ns in self.successes:
2202 actual_ns = parse_args(args_string.split())
2203 self.assertEqual(actual_ns, expected_ns)
2204
2205 def test_usage_when_not_required(self):
2206 format_usage = self.get_parser(required=False).format_usage
2207 expected_usage = self.usage_when_not_required
2208 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2209
2210 def test_usage_when_required(self):
2211 format_usage = self.get_parser(required=True).format_usage
2212 expected_usage = self.usage_when_required
2213 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2214
2215 def test_help_when_not_required(self):
2216 format_help = self.get_parser(required=False).format_help
2217 help = self.usage_when_not_required + self.help
2218 self.assertEqual(format_help(), textwrap.dedent(help))
2219
2220 def test_help_when_required(self):
2221 format_help = self.get_parser(required=True).format_help
2222 help = self.usage_when_required + self.help
2223 self.assertEqual(format_help(), textwrap.dedent(help))
2224
2225
2226class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2227
2228 def get_parser(self, required=None):
2229 parser = ErrorRaisingArgumentParser(prog='PROG')
2230 group = parser.add_mutually_exclusive_group(required=required)
2231 group.add_argument('--bar', help='bar help')
2232 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2233 return parser
2234
2235 failures = ['--bar X --baz Y', '--bar X --baz']
2236 successes = [
2237 ('--bar X', NS(bar='X', baz=None)),
2238 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2239 ('--baz Y', NS(bar=None, baz='Y')),
2240 ('--baz', NS(bar=None, baz='Z')),
2241 ]
2242 successes_when_not_required = [
2243 ('', NS(bar=None, baz=None)),
2244 ]
2245
2246 usage_when_not_required = '''\
2247 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2248 '''
2249 usage_when_required = '''\
2250 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2251 '''
2252 help = '''\
2253
2254 optional arguments:
2255 -h, --help show this help message and exit
2256 --bar BAR bar help
2257 --baz [BAZ] baz help
2258 '''
2259
2260
2261class TestMutuallyExclusiveLong(MEMixin, TestCase):
2262
2263 def get_parser(self, required=None):
2264 parser = ErrorRaisingArgumentParser(prog='PROG')
2265 parser.add_argument('--abcde', help='abcde help')
2266 parser.add_argument('--fghij', help='fghij help')
2267 group = parser.add_mutually_exclusive_group(required=required)
2268 group.add_argument('--klmno', help='klmno help')
2269 group.add_argument('--pqrst', help='pqrst help')
2270 return parser
2271
2272 failures = ['--klmno X --pqrst Y']
2273 successes = [
2274 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2275 ('--abcde Y --klmno X',
2276 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2277 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2278 ('--pqrst X --fghij Y',
2279 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2280 ]
2281 successes_when_not_required = [
2282 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2283 ]
2284
2285 usage_when_not_required = '''\
2286 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2287 [--klmno KLMNO | --pqrst PQRST]
2288 '''
2289 usage_when_required = '''\
2290 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2291 (--klmno KLMNO | --pqrst PQRST)
2292 '''
2293 help = '''\
2294
2295 optional arguments:
2296 -h, --help show this help message and exit
2297 --abcde ABCDE abcde help
2298 --fghij FGHIJ fghij help
2299 --klmno KLMNO klmno help
2300 --pqrst PQRST pqrst help
2301 '''
2302
2303
2304class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2305
2306 def get_parser(self, required):
2307 parser = ErrorRaisingArgumentParser(prog='PROG')
2308 group = parser.add_mutually_exclusive_group(required=required)
2309 group.add_argument('-x', help=argparse.SUPPRESS)
2310 group.add_argument('-y', action='store_false', help='y help')
2311 return parser
2312
2313 failures = ['-x X -y']
2314 successes = [
2315 ('-x X', NS(x='X', y=True)),
2316 ('-x X -x Y', NS(x='Y', y=True)),
2317 ('-y', NS(x=None, y=False)),
2318 ]
2319 successes_when_not_required = [
2320 ('', NS(x=None, y=True)),
2321 ]
2322
2323 usage_when_not_required = '''\
2324 usage: PROG [-h] [-y]
2325 '''
2326 usage_when_required = '''\
2327 usage: PROG [-h] -y
2328 '''
2329 help = '''\
2330
2331 optional arguments:
2332 -h, --help show this help message and exit
2333 -y y help
2334 '''
2335
2336
2337class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2338
2339 def get_parser(self, required):
2340 parser = ErrorRaisingArgumentParser(prog='PROG')
2341 group = parser.add_mutually_exclusive_group(required=required)
2342 add = group.add_argument
2343 add('--spam', action='store_true', help=argparse.SUPPRESS)
2344 add('--badger', action='store_false', help=argparse.SUPPRESS)
2345 add('--bladder', help=argparse.SUPPRESS)
2346 return parser
2347
2348 failures = [
2349 '--spam --badger',
2350 '--badger --bladder B',
2351 '--bladder B --spam',
2352 ]
2353 successes = [
2354 ('--spam', NS(spam=True, badger=True, bladder=None)),
2355 ('--badger', NS(spam=False, badger=False, bladder=None)),
2356 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2357 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2358 ]
2359 successes_when_not_required = [
2360 ('', NS(spam=False, badger=True, bladder=None)),
2361 ]
2362
2363 usage_when_required = usage_when_not_required = '''\
2364 usage: PROG [-h]
2365 '''
2366 help = '''\
2367
2368 optional arguments:
2369 -h, --help show this help message and exit
2370 '''
2371
2372
2373class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2374
2375 def get_parser(self, required):
2376 parser = ErrorRaisingArgumentParser(prog='PROG')
2377 group = parser.add_mutually_exclusive_group(required=required)
2378 group.add_argument('--foo', action='store_true', help='FOO')
2379 group.add_argument('--spam', help='SPAM')
2380 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2381 return parser
2382
2383 failures = [
2384 '--foo --spam S',
2385 '--spam S X',
2386 'X --foo',
2387 'X Y Z --spam S',
2388 '--foo X Y',
2389 ]
2390 successes = [
2391 ('--foo', NS(foo=True, spam=None, badger='X')),
2392 ('--spam S', NS(foo=False, spam='S', badger='X')),
2393 ('X', NS(foo=False, spam=None, badger=['X'])),
2394 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2395 ]
2396 successes_when_not_required = [
2397 ('', NS(foo=False, spam=None, badger='X')),
2398 ]
2399
2400 usage_when_not_required = '''\
2401 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2402 '''
2403 usage_when_required = '''\
2404 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2405 '''
2406 help = '''\
2407
2408 positional arguments:
2409 badger BADGER
2410
2411 optional arguments:
2412 -h, --help show this help message and exit
2413 --foo FOO
2414 --spam SPAM SPAM
2415 '''
2416
2417
2418class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2419
2420 def get_parser(self, required):
2421 parser = ErrorRaisingArgumentParser(prog='PROG')
2422 parser.add_argument('-x', action='store_true', help='x help')
2423 group = parser.add_mutually_exclusive_group(required=required)
2424 group.add_argument('-a', action='store_true', help='a help')
2425 group.add_argument('-b', action='store_true', help='b help')
2426 parser.add_argument('-y', action='store_true', help='y help')
2427 group.add_argument('-c', action='store_true', help='c help')
2428 return parser
2429
2430 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2431 successes = [
2432 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2433 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2434 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2435 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2436 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2437 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2438 ]
2439 successes_when_not_required = [
2440 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2441 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2442 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2443 ]
2444
2445 usage_when_required = usage_when_not_required = '''\
2446 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2447 '''
2448 help = '''\
2449
2450 optional arguments:
2451 -h, --help show this help message and exit
2452 -x x help
2453 -a a help
2454 -b b help
2455 -y y help
2456 -c c help
2457 '''
2458
2459
2460class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2461
2462 def get_parser(self, required):
2463 parser = ErrorRaisingArgumentParser(prog='PROG')
2464 parser.add_argument('x', help='x help')
2465 parser.add_argument('-y', action='store_true', help='y help')
2466 group = parser.add_mutually_exclusive_group(required=required)
2467 group.add_argument('a', nargs='?', help='a help')
2468 group.add_argument('-b', action='store_true', help='b help')
2469 group.add_argument('-c', action='store_true', help='c help')
2470 return parser
2471
2472 failures = ['X A -b', '-b -c', '-c X A']
2473 successes = [
2474 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2475 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2476 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2477 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2478 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2479 ]
2480 successes_when_not_required = [
2481 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2482 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2483 ]
2484
2485 usage_when_required = usage_when_not_required = '''\
2486 usage: PROG [-h] [-y] [-b] [-c] x [a]
2487 '''
2488 help = '''\
2489
2490 positional arguments:
2491 x x help
2492 a a help
2493
2494 optional arguments:
2495 -h, --help show this help message and exit
2496 -y y help
2497 -b b help
2498 -c c help
2499 '''
2500
2501# =================================================
2502# Mutually exclusive group in parent parser tests
2503# =================================================
2504
2505class MEPBase(object):
2506
2507 def get_parser(self, required=None):
2508 parent = super(MEPBase, self).get_parser(required=required)
2509 parser = ErrorRaisingArgumentParser(
2510 prog=parent.prog, add_help=False, parents=[parent])
2511 return parser
2512
2513
2514class TestMutuallyExclusiveGroupErrorsParent(
2515 MEPBase, TestMutuallyExclusiveGroupErrors):
2516 pass
2517
2518
2519class TestMutuallyExclusiveSimpleParent(
2520 MEPBase, TestMutuallyExclusiveSimple):
2521 pass
2522
2523
2524class TestMutuallyExclusiveLongParent(
2525 MEPBase, TestMutuallyExclusiveLong):
2526 pass
2527
2528
2529class TestMutuallyExclusiveFirstSuppressedParent(
2530 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2531 pass
2532
2533
2534class TestMutuallyExclusiveManySuppressedParent(
2535 MEPBase, TestMutuallyExclusiveManySuppressed):
2536 pass
2537
2538
2539class TestMutuallyExclusiveOptionalAndPositionalParent(
2540 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2541 pass
2542
2543
2544class TestMutuallyExclusiveOptionalsMixedParent(
2545 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2546 pass
2547
2548
2549class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2550 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2551 pass
2552
2553# =================
2554# Set default tests
2555# =================
2556
2557class TestSetDefaults(TestCase):
2558
2559 def test_set_defaults_no_args(self):
2560 parser = ErrorRaisingArgumentParser()
2561 parser.set_defaults(x='foo')
2562 parser.set_defaults(y='bar', z=1)
2563 self.assertEqual(NS(x='foo', y='bar', z=1),
2564 parser.parse_args([]))
2565 self.assertEqual(NS(x='foo', y='bar', z=1),
2566 parser.parse_args([], NS()))
2567 self.assertEqual(NS(x='baz', y='bar', z=1),
2568 parser.parse_args([], NS(x='baz')))
2569 self.assertEqual(NS(x='baz', y='bar', z=2),
2570 parser.parse_args([], NS(x='baz', z=2)))
2571
2572 def test_set_defaults_with_args(self):
2573 parser = ErrorRaisingArgumentParser()
2574 parser.set_defaults(x='foo', y='bar')
2575 parser.add_argument('-x', default='xfoox')
2576 self.assertEqual(NS(x='xfoox', y='bar'),
2577 parser.parse_args([]))
2578 self.assertEqual(NS(x='xfoox', y='bar'),
2579 parser.parse_args([], NS()))
2580 self.assertEqual(NS(x='baz', y='bar'),
2581 parser.parse_args([], NS(x='baz')))
2582 self.assertEqual(NS(x='1', y='bar'),
2583 parser.parse_args('-x 1'.split()))
2584 self.assertEqual(NS(x='1', y='bar'),
2585 parser.parse_args('-x 1'.split(), NS()))
2586 self.assertEqual(NS(x='1', y='bar'),
2587 parser.parse_args('-x 1'.split(), NS(x='baz')))
2588
2589 def test_set_defaults_subparsers(self):
2590 parser = ErrorRaisingArgumentParser()
2591 parser.set_defaults(x='foo')
2592 subparsers = parser.add_subparsers()
2593 parser_a = subparsers.add_parser('a')
2594 parser_a.set_defaults(y='bar')
2595 self.assertEqual(NS(x='foo', y='bar'),
2596 parser.parse_args('a'.split()))
2597
2598 def test_set_defaults_parents(self):
2599 parent = ErrorRaisingArgumentParser(add_help=False)
2600 parent.set_defaults(x='foo')
2601 parser = ErrorRaisingArgumentParser(parents=[parent])
2602 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2603
2604 def test_set_defaults_same_as_add_argument(self):
2605 parser = ErrorRaisingArgumentParser()
2606 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2607 parser.add_argument('-w')
2608 parser.add_argument('-x', default='XX')
2609 parser.add_argument('y', nargs='?')
2610 parser.add_argument('z', nargs='?', default='ZZ')
2611
2612 # defaults set previously
2613 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2614 parser.parse_args([]))
2615
2616 # reset defaults
2617 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2618 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2619 parser.parse_args([]))
2620
2621 def test_set_defaults_same_as_add_argument_group(self):
2622 parser = ErrorRaisingArgumentParser()
2623 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2624 group = parser.add_argument_group('foo')
2625 group.add_argument('-w')
2626 group.add_argument('-x', default='XX')
2627 group.add_argument('y', nargs='?')
2628 group.add_argument('z', nargs='?', default='ZZ')
2629
2630
2631 # defaults set previously
2632 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2633 parser.parse_args([]))
2634
2635 # reset defaults
2636 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2637 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2638 parser.parse_args([]))
2639
2640# =================
2641# Get default tests
2642# =================
2643
2644class TestGetDefault(TestCase):
2645
2646 def test_get_default(self):
2647 parser = ErrorRaisingArgumentParser()
2648 self.assertEqual(None, parser.get_default("foo"))
2649 self.assertEqual(None, parser.get_default("bar"))
2650
2651 parser.add_argument("--foo")
2652 self.assertEqual(None, parser.get_default("foo"))
2653 self.assertEqual(None, parser.get_default("bar"))
2654
2655 parser.add_argument("--bar", type=int, default=42)
2656 self.assertEqual(None, parser.get_default("foo"))
2657 self.assertEqual(42, parser.get_default("bar"))
2658
2659 parser.set_defaults(foo="badger")
2660 self.assertEqual("badger", parser.get_default("foo"))
2661 self.assertEqual(42, parser.get_default("bar"))
2662
2663# ==========================
2664# Namespace 'contains' tests
2665# ==========================
2666
2667class TestNamespaceContainsSimple(TestCase):
2668
2669 def test_empty(self):
2670 ns = argparse.Namespace()
2671 self.assertEquals('' in ns, False)
2672 self.assertEquals('' not in ns, True)
2673 self.assertEquals('x' in ns, False)
2674
2675 def test_non_empty(self):
2676 ns = argparse.Namespace(x=1, y=2)
2677 self.assertEquals('x' in ns, True)
2678 self.assertEquals('x' not in ns, False)
2679 self.assertEquals('y' in ns, True)
2680 self.assertEquals('' in ns, False)
2681 self.assertEquals('xx' in ns, False)
2682 self.assertEquals('z' in ns, False)
2683
2684# =====================
2685# Help formatting tests
2686# =====================
2687
2688class TestHelpFormattingMetaclass(type):
2689
2690 def __init__(cls, name, bases, bodydict):
2691 if name == 'HelpTestCase':
2692 return
2693
2694 class AddTests(object):
2695
2696 def __init__(self, test_class, func_suffix, std_name):
2697 self.func_suffix = func_suffix
2698 self.std_name = std_name
2699
2700 for test_func in [self.test_format,
2701 self.test_print,
2702 self.test_print_file]:
2703 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2704
2705 def test_wrapper(self, test_func=test_func):
2706 test_func(self)
2707 try:
2708 test_wrapper.__name__ = test_name
2709 except TypeError:
2710 pass
2711 setattr(test_class, test_name, test_wrapper)
2712
2713 def _get_parser(self, tester):
2714 parser = argparse.ArgumentParser(
2715 *tester.parser_signature.args,
2716 **tester.parser_signature.kwargs)
2717 for argument_sig in tester.argument_signatures:
2718 parser.add_argument(*argument_sig.args,
2719 **argument_sig.kwargs)
2720 group_signatures = tester.argument_group_signatures
2721 for group_sig, argument_sigs in group_signatures:
2722 group = parser.add_argument_group(*group_sig.args,
2723 **group_sig.kwargs)
2724 for argument_sig in argument_sigs:
2725 group.add_argument(*argument_sig.args,
2726 **argument_sig.kwargs)
2727 return parser
2728
2729 def _test(self, tester, parser_text):
2730 expected_text = getattr(tester, self.func_suffix)
2731 expected_text = textwrap.dedent(expected_text)
2732 if expected_text != parser_text:
2733 print(repr(expected_text))
2734 print(repr(parser_text))
2735 for char1, char2 in zip(expected_text, parser_text):
2736 if char1 != char2:
2737 print('first diff: %r %r' % (char1, char2))
2738 break
2739 tester.assertEqual(expected_text, parser_text)
2740
2741 def test_format(self, tester):
2742 parser = self._get_parser(tester)
2743 format = getattr(parser, 'format_%s' % self.func_suffix)
2744 self._test(tester, format())
2745
2746 def test_print(self, tester):
2747 parser = self._get_parser(tester)
2748 print_ = getattr(parser, 'print_%s' % self.func_suffix)
2749 old_stream = getattr(sys, self.std_name)
Michael Foord91a2c892010-04-08 00:04:24 +00002750 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Petersona39e9662010-03-02 22:05:59 +00002751 try:
2752 print_()
2753 parser_text = getattr(sys, self.std_name).getvalue()
2754 finally:
2755 setattr(sys, self.std_name, old_stream)
2756 self._test(tester, parser_text)
2757
2758 def test_print_file(self, tester):
2759 parser = self._get_parser(tester)
2760 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Michael Foord91a2c892010-04-08 00:04:24 +00002761 sfile = StdIOBuffer()
Benjamin Petersona39e9662010-03-02 22:05:59 +00002762 print_(sfile)
2763 parser_text = sfile.getvalue()
2764 self._test(tester, parser_text)
2765
2766 # add tests for {format,print}_{usage,help,version}
2767 for func_suffix, std_name in [('usage', 'stdout'),
2768 ('help', 'stdout'),
2769 ('version', 'stderr')]:
2770 AddTests(cls, func_suffix, std_name)
2771
2772bases = TestCase,
2773HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
2774
2775
2776class TestHelpBiggerOptionals(HelpTestCase):
2777 """Make sure that argument help aligns when options are longer"""
2778
2779 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2780 epilog='EPILOG', version='0.1')
2781 argument_signatures = [
2782 Sig('-x', action='store_true', help='X HELP'),
2783 Sig('--y', help='Y HELP'),
2784 Sig('foo', help='FOO HELP'),
2785 Sig('bar', help='BAR HELP'),
2786 ]
2787 argument_group_signatures = []
2788 usage = '''\
2789 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
2790 '''
2791 help = usage + '''\
2792
2793 DESCRIPTION
2794
2795 positional arguments:
2796 foo FOO HELP
2797 bar BAR HELP
2798
2799 optional arguments:
2800 -h, --help show this help message and exit
2801 -v, --version show program's version number and exit
2802 -x X HELP
2803 --y Y Y HELP
2804
2805 EPILOG
2806 '''
2807 version = '''\
2808 0.1
2809 '''
2810
2811
2812class TestHelpBiggerOptionalGroups(HelpTestCase):
2813 """Make sure that argument help aligns when options are longer"""
2814
2815 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2816 epilog='EPILOG', version='0.1')
2817 argument_signatures = [
2818 Sig('-x', action='store_true', help='X HELP'),
2819 Sig('--y', help='Y HELP'),
2820 Sig('foo', help='FOO HELP'),
2821 Sig('bar', help='BAR HELP'),
2822 ]
2823 argument_group_signatures = [
2824 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2825 Sig('baz', help='BAZ HELP'),
2826 Sig('-z', nargs='+', help='Z HELP')]),
2827 ]
2828 usage = '''\
2829 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2830 '''
2831 help = usage + '''\
2832
2833 DESCRIPTION
2834
2835 positional arguments:
2836 foo FOO HELP
2837 bar BAR HELP
2838
2839 optional arguments:
2840 -h, --help show this help message and exit
2841 -v, --version show program's version number and exit
2842 -x X HELP
2843 --y Y Y HELP
2844
2845 GROUP TITLE:
2846 GROUP DESCRIPTION
2847
2848 baz BAZ HELP
2849 -z Z [Z ...] Z HELP
2850
2851 EPILOG
2852 '''
2853 version = '''\
2854 0.1
2855 '''
2856
2857
2858class TestHelpBiggerPositionals(HelpTestCase):
2859 """Make sure that help aligns when arguments are longer"""
2860
2861 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2862 argument_signatures = [
2863 Sig('-x', action='store_true', help='X HELP'),
2864 Sig('--y', help='Y HELP'),
2865 Sig('ekiekiekifekang', help='EKI HELP'),
2866 Sig('bar', help='BAR HELP'),
2867 ]
2868 argument_group_signatures = []
2869 usage = '''\
2870 usage: USAGE
2871 '''
2872 help = usage + '''\
2873
2874 DESCRIPTION
2875
2876 positional arguments:
2877 ekiekiekifekang EKI HELP
2878 bar BAR HELP
2879
2880 optional arguments:
2881 -h, --help show this help message and exit
2882 -x X HELP
2883 --y Y Y HELP
2884 '''
2885
2886 version = ''
2887
2888
2889class TestHelpReformatting(HelpTestCase):
2890 """Make sure that text after short names starts on the first line"""
2891
2892 parser_signature = Sig(
2893 prog='PROG',
2894 description=' oddly formatted\n'
2895 'description\n'
2896 '\n'
2897 'that is so long that it should go onto multiple '
2898 'lines when wrapped')
2899 argument_signatures = [
2900 Sig('-x', metavar='XX', help='oddly\n'
2901 ' formatted -x help'),
2902 Sig('y', metavar='yyy', help='normal y help'),
2903 ]
2904 argument_group_signatures = [
2905 (Sig('title', description='\n'
2906 ' oddly formatted group\n'
2907 '\n'
2908 'description'),
2909 [Sig('-a', action='store_true',
2910 help=' oddly \n'
2911 'formatted -a help \n'
2912 ' again, so long that it should be wrapped over '
2913 'multiple lines')]),
2914 ]
2915 usage = '''\
2916 usage: PROG [-h] [-x XX] [-a] yyy
2917 '''
2918 help = usage + '''\
2919
2920 oddly formatted description that is so long that it should go onto \
2921multiple
2922 lines when wrapped
2923
2924 positional arguments:
2925 yyy normal y help
2926
2927 optional arguments:
2928 -h, --help show this help message and exit
2929 -x XX oddly formatted -x help
2930
2931 title:
2932 oddly formatted group description
2933
2934 -a oddly formatted -a help again, so long that it should \
2935be wrapped
2936 over multiple lines
2937 '''
2938 version = ''
2939
2940
2941class TestHelpWrappingShortNames(HelpTestCase):
2942 """Make sure that text after short names starts on the first line"""
2943
2944 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
2945 argument_signatures = [
2946 Sig('-x', metavar='XX', help='XHH HX' * 20),
2947 Sig('y', metavar='yyy', help='YH YH' * 20),
2948 ]
2949 argument_group_signatures = [
2950 (Sig('ALPHAS'), [
2951 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
2952 ]
2953 usage = '''\
2954 usage: PROG [-h] [-x XX] [-a] yyy
2955 '''
2956 help = usage + '''\
2957
2958 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
2959DD DD DD
2960 DD DD DD DD D
2961
2962 positional arguments:
2963 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
2964YHYH YHYH
2965 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
2966
2967 optional arguments:
2968 -h, --help show this help message and exit
2969 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
2970HXXHH HXXHH
2971 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
2972
2973 ALPHAS:
2974 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
2975HHAAHHH
2976 HHAAHHH HHAAHHH HHA
2977 '''
2978 version = ''
2979
2980
2981class TestHelpWrappingLongNames(HelpTestCase):
2982 """Make sure that text after long names starts on the next line"""
2983
2984 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
2985 version='V V'*30)
2986 argument_signatures = [
2987 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
2988 Sig('y', metavar='y' * 25, help='YH YH' * 20),
2989 ]
2990 argument_group_signatures = [
2991 (Sig('ALPHAS'), [
2992 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
2993 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
2994 ]
2995 usage = '''\
2996 usage: USAGE
2997 '''
2998 help = usage + '''\
2999
3000 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3001DD DD DD
3002 DD DD DD DD D
3003
3004 positional arguments:
3005 yyyyyyyyyyyyyyyyyyyyyyyyy
3006 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3007YHYH YHYH
3008 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3009
3010 optional arguments:
3011 -h, --help show this help message and exit
3012 -v, --version show program's version number and exit
3013 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3014 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3015XHXH XHXH
3016 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3017
3018 ALPHAS:
3019 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3020 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3021AHAH AHAH
3022 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3023 zzzzzzzzzzzzzzzzzzzzzzzzz
3024 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3025ZHZH ZHZH
3026 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3027 '''
3028 version = '''\
3029 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3030VV VV VV
3031 VV VV VV VV V
3032 '''
3033
3034
3035class TestHelpUsage(HelpTestCase):
3036 """Test basic usage messages"""
3037
3038 parser_signature = Sig(prog='PROG')
3039 argument_signatures = [
3040 Sig('-w', nargs='+', help='w'),
3041 Sig('-x', nargs='*', help='x'),
3042 Sig('a', help='a'),
3043 Sig('b', help='b', nargs=2),
3044 Sig('c', help='c', nargs='?'),
3045 ]
3046 argument_group_signatures = [
3047 (Sig('group'), [
3048 Sig('-y', nargs='?', help='y'),
3049 Sig('-z', nargs=3, help='z'),
3050 Sig('d', help='d', nargs='*'),
3051 Sig('e', help='e', nargs='+'),
3052 ])
3053 ]
3054 usage = '''\
3055 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3056 a b b [c] [d [d ...]] e [e ...]
3057 '''
3058 help = usage + '''\
3059
3060 positional arguments:
3061 a a
3062 b b
3063 c c
3064
3065 optional arguments:
3066 -h, --help show this help message and exit
3067 -w W [W ...] w
3068 -x [X [X ...]] x
3069
3070 group:
3071 -y [Y] y
3072 -z Z Z Z z
3073 d d
3074 e e
3075 '''
3076 version = ''
3077
3078
3079class TestHelpOnlyUserGroups(HelpTestCase):
3080 """Test basic usage messages"""
3081
3082 parser_signature = Sig(prog='PROG', add_help=False)
3083 argument_signatures = []
3084 argument_group_signatures = [
3085 (Sig('xxxx'), [
3086 Sig('-x', help='x'),
3087 Sig('a', help='a'),
3088 ]),
3089 (Sig('yyyy'), [
3090 Sig('b', help='b'),
3091 Sig('-y', help='y'),
3092 ]),
3093 ]
3094 usage = '''\
3095 usage: PROG [-x X] [-y Y] a b
3096 '''
3097 help = usage + '''\
3098
3099 xxxx:
3100 -x X x
3101 a a
3102
3103 yyyy:
3104 b b
3105 -y Y y
3106 '''
3107 version = ''
3108
3109
3110class TestHelpUsageLongProg(HelpTestCase):
3111 """Test usage messages where the prog is long"""
3112
3113 parser_signature = Sig(prog='P' * 60)
3114 argument_signatures = [
3115 Sig('-w', metavar='W'),
3116 Sig('-x', metavar='X'),
3117 Sig('a'),
3118 Sig('b'),
3119 ]
3120 argument_group_signatures = []
3121 usage = '''\
3122 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3123 [-h] [-w W] [-x X] a b
3124 '''
3125 help = usage + '''\
3126
3127 positional arguments:
3128 a
3129 b
3130
3131 optional arguments:
3132 -h, --help show this help message and exit
3133 -w W
3134 -x X
3135 '''
3136 version = ''
3137
3138
3139class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3140 """Test usage messages where the prog is long and the optionals wrap"""
3141
3142 parser_signature = Sig(prog='P' * 60)
3143 argument_signatures = [
3144 Sig('-w', metavar='W' * 25),
3145 Sig('-x', metavar='X' * 25),
3146 Sig('-y', metavar='Y' * 25),
3147 Sig('-z', metavar='Z' * 25),
3148 Sig('a'),
3149 Sig('b'),
3150 ]
3151 argument_group_signatures = []
3152 usage = '''\
3153 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3154 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3155[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3156 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3157 a b
3158 '''
3159 help = usage + '''\
3160
3161 positional arguments:
3162 a
3163 b
3164
3165 optional arguments:
3166 -h, --help show this help message and exit
3167 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3168 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3169 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3170 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3171 '''
3172 version = ''
3173
3174
3175class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3176 """Test usage messages where the prog is long and the positionals wrap"""
3177
3178 parser_signature = Sig(prog='P' * 60, add_help=False)
3179 argument_signatures = [
3180 Sig('a' * 25),
3181 Sig('b' * 25),
3182 Sig('c' * 25),
3183 ]
3184 argument_group_signatures = []
3185 usage = '''\
3186 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3187 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3188 ccccccccccccccccccccccccc
3189 '''
3190 help = usage + '''\
3191
3192 positional arguments:
3193 aaaaaaaaaaaaaaaaaaaaaaaaa
3194 bbbbbbbbbbbbbbbbbbbbbbbbb
3195 ccccccccccccccccccccccccc
3196 '''
3197 version = ''
3198
3199
3200class TestHelpUsageOptionalsWrap(HelpTestCase):
3201 """Test usage messages where the optionals wrap"""
3202
3203 parser_signature = Sig(prog='PROG')
3204 argument_signatures = [
3205 Sig('-w', metavar='W' * 25),
3206 Sig('-x', metavar='X' * 25),
3207 Sig('-y', metavar='Y' * 25),
3208 Sig('-z', metavar='Z' * 25),
3209 Sig('a'),
3210 Sig('b'),
3211 Sig('c'),
3212 ]
3213 argument_group_signatures = []
3214 usage = '''\
3215 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3216[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3217 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3218[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3219 a b c
3220 '''
3221 help = usage + '''\
3222
3223 positional arguments:
3224 a
3225 b
3226 c
3227
3228 optional arguments:
3229 -h, --help show this help message and exit
3230 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3231 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3232 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3233 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3234 '''
3235 version = ''
3236
3237
3238class TestHelpUsagePositionalsWrap(HelpTestCase):
3239 """Test usage messages where the positionals wrap"""
3240
3241 parser_signature = Sig(prog='PROG')
3242 argument_signatures = [
3243 Sig('-x'),
3244 Sig('-y'),
3245 Sig('-z'),
3246 Sig('a' * 25),
3247 Sig('b' * 25),
3248 Sig('c' * 25),
3249 ]
3250 argument_group_signatures = []
3251 usage = '''\
3252 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3253 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3254 ccccccccccccccccccccccccc
3255 '''
3256 help = usage + '''\
3257
3258 positional arguments:
3259 aaaaaaaaaaaaaaaaaaaaaaaaa
3260 bbbbbbbbbbbbbbbbbbbbbbbbb
3261 ccccccccccccccccccccccccc
3262
3263 optional arguments:
3264 -h, --help show this help message and exit
3265 -x X
3266 -y Y
3267 -z Z
3268 '''
3269 version = ''
3270
3271
3272class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3273 """Test usage messages where the optionals and positionals wrap"""
3274
3275 parser_signature = Sig(prog='PROG')
3276 argument_signatures = [
3277 Sig('-x', metavar='X' * 25),
3278 Sig('-y', metavar='Y' * 25),
3279 Sig('-z', metavar='Z' * 25),
3280 Sig('a' * 25),
3281 Sig('b' * 25),
3282 Sig('c' * 25),
3283 ]
3284 argument_group_signatures = []
3285 usage = '''\
3286 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3287[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3288 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3289 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3290 ccccccccccccccccccccccccc
3291 '''
3292 help = usage + '''\
3293
3294 positional arguments:
3295 aaaaaaaaaaaaaaaaaaaaaaaaa
3296 bbbbbbbbbbbbbbbbbbbbbbbbb
3297 ccccccccccccccccccccccccc
3298
3299 optional arguments:
3300 -h, --help show this help message and exit
3301 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3302 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3303 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3304 '''
3305 version = ''
3306
3307
3308class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3309 """Test usage messages where there are only optionals and they wrap"""
3310
3311 parser_signature = Sig(prog='PROG')
3312 argument_signatures = [
3313 Sig('-x', metavar='X' * 25),
3314 Sig('-y', metavar='Y' * 25),
3315 Sig('-z', metavar='Z' * 25),
3316 ]
3317 argument_group_signatures = []
3318 usage = '''\
3319 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3320[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3321 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3322 '''
3323 help = usage + '''\
3324
3325 optional arguments:
3326 -h, --help show this help message and exit
3327 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3328 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3329 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3330 '''
3331 version = ''
3332
3333
3334class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3335 """Test usage messages where there are only positionals and they wrap"""
3336
3337 parser_signature = Sig(prog='PROG', add_help=False)
3338 argument_signatures = [
3339 Sig('a' * 25),
3340 Sig('b' * 25),
3341 Sig('c' * 25),
3342 ]
3343 argument_group_signatures = []
3344 usage = '''\
3345 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3346 ccccccccccccccccccccccccc
3347 '''
3348 help = usage + '''\
3349
3350 positional arguments:
3351 aaaaaaaaaaaaaaaaaaaaaaaaa
3352 bbbbbbbbbbbbbbbbbbbbbbbbb
3353 ccccccccccccccccccccccccc
3354 '''
3355 version = ''
3356
3357
3358class TestHelpVariableExpansion(HelpTestCase):
3359 """Test that variables are expanded properly in help messages"""
3360
3361 parser_signature = Sig(prog='PROG')
3362 argument_signatures = [
3363 Sig('-x', type=int,
3364 help='x %(prog)s %(default)s %(type)s %%'),
3365 Sig('-y', action='store_const', default=42, const='XXX',
3366 help='y %(prog)s %(default)s %(const)s'),
3367 Sig('--foo', choices='abc',
3368 help='foo %(prog)s %(default)s %(choices)s'),
3369 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3370 help='bar %(prog)s %(default)s %(dest)s'),
3371 Sig('spam', help='spam %(prog)s %(default)s'),
3372 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3373 ]
3374 argument_group_signatures = [
3375 (Sig('group'), [
3376 Sig('-a', help='a %(prog)s %(default)s'),
3377 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3378 ])
3379 ]
3380 usage = ('''\
3381 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3382 spam badger
3383 ''')
3384 help = usage + '''\
3385
3386 positional arguments:
3387 spam spam PROG None
3388 badger badger PROG 0.5
3389
3390 optional arguments:
3391 -h, --help show this help message and exit
3392 -x X x PROG None int %
3393 -y y PROG 42 XXX
3394 --foo {a,b,c} foo PROG None a, b, c
3395 --bar BBB bar PROG baz bar
3396
3397 group:
3398 -a A a PROG None
3399 -b B b PROG -1
3400 '''
3401 version = ''
3402
3403
3404class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3405 """Test that variables are expanded properly when usage= is present"""
3406
3407 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3408 argument_signatures = []
3409 argument_group_signatures = []
3410 usage = ('''\
3411 usage: PROG FOO
3412 ''')
3413 help = usage + '''\
3414
3415 optional arguments:
3416 -h, --help show this help message and exit
3417 '''
3418 version = ''
3419
3420
3421class TestHelpVariableExpansionNoArguments(HelpTestCase):
3422 """Test that variables are expanded properly with no arguments"""
3423
3424 parser_signature = Sig(prog='PROG', add_help=False)
3425 argument_signatures = []
3426 argument_group_signatures = []
3427 usage = ('''\
3428 usage: PROG
3429 ''')
3430 help = usage
3431 version = ''
3432
3433
3434class TestHelpSuppressUsage(HelpTestCase):
3435 """Test that items can be suppressed in usage messages"""
3436
3437 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3438 argument_signatures = [
3439 Sig('--foo', help='foo help'),
3440 Sig('spam', help='spam help'),
3441 ]
3442 argument_group_signatures = []
3443 help = '''\
3444 positional arguments:
3445 spam spam help
3446
3447 optional arguments:
3448 -h, --help show this help message and exit
3449 --foo FOO foo help
3450 '''
3451 usage = ''
3452 version = ''
3453
3454
3455class TestHelpSuppressOptional(HelpTestCase):
3456 """Test that optional arguments can be suppressed in help messages"""
3457
3458 parser_signature = Sig(prog='PROG', add_help=False)
3459 argument_signatures = [
3460 Sig('--foo', help=argparse.SUPPRESS),
3461 Sig('spam', help='spam help'),
3462 ]
3463 argument_group_signatures = []
3464 usage = '''\
3465 usage: PROG spam
3466 '''
3467 help = usage + '''\
3468
3469 positional arguments:
3470 spam spam help
3471 '''
3472 version = ''
3473
3474
3475class TestHelpSuppressOptionalGroup(HelpTestCase):
3476 """Test that optional groups can be suppressed in help messages"""
3477
3478 parser_signature = Sig(prog='PROG')
3479 argument_signatures = [
3480 Sig('--foo', help='foo help'),
3481 Sig('spam', help='spam help'),
3482 ]
3483 argument_group_signatures = [
3484 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3485 ]
3486 usage = '''\
3487 usage: PROG [-h] [--foo FOO] spam
3488 '''
3489 help = usage + '''\
3490
3491 positional arguments:
3492 spam spam help
3493
3494 optional arguments:
3495 -h, --help show this help message and exit
3496 --foo FOO foo help
3497 '''
3498 version = ''
3499
3500
3501class TestHelpSuppressPositional(HelpTestCase):
3502 """Test that positional arguments can be suppressed in help messages"""
3503
3504 parser_signature = Sig(prog='PROG')
3505 argument_signatures = [
3506 Sig('--foo', help='foo help'),
3507 Sig('spam', help=argparse.SUPPRESS),
3508 ]
3509 argument_group_signatures = []
3510 usage = '''\
3511 usage: PROG [-h] [--foo FOO]
3512 '''
3513 help = usage + '''\
3514
3515 optional arguments:
3516 -h, --help show this help message and exit
3517 --foo FOO foo help
3518 '''
3519 version = ''
3520
3521
3522class TestHelpRequiredOptional(HelpTestCase):
3523 """Test that required options don't look optional"""
3524
3525 parser_signature = Sig(prog='PROG')
3526 argument_signatures = [
3527 Sig('--foo', required=True, help='foo help'),
3528 ]
3529 argument_group_signatures = []
3530 usage = '''\
3531 usage: PROG [-h] --foo FOO
3532 '''
3533 help = usage + '''\
3534
3535 optional arguments:
3536 -h, --help show this help message and exit
3537 --foo FOO foo help
3538 '''
3539 version = ''
3540
3541
3542class TestHelpAlternatePrefixChars(HelpTestCase):
3543 """Test that options display with different prefix characters"""
3544
3545 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3546 argument_signatures = [
3547 Sig('^^foo', action='store_true', help='foo help'),
3548 Sig(';b', ';;bar', help='bar help'),
3549 ]
3550 argument_group_signatures = []
3551 usage = '''\
3552 usage: PROG [^^foo] [;b BAR]
3553 '''
3554 help = usage + '''\
3555
3556 optional arguments:
3557 ^^foo foo help
3558 ;b BAR, ;;bar BAR bar help
3559 '''
3560 version = ''
3561
3562
3563class TestHelpNoHelpOptional(HelpTestCase):
3564 """Test that the --help argument can be suppressed help messages"""
3565
3566 parser_signature = Sig(prog='PROG', add_help=False)
3567 argument_signatures = [
3568 Sig('--foo', help='foo help'),
3569 Sig('spam', help='spam help'),
3570 ]
3571 argument_group_signatures = []
3572 usage = '''\
3573 usage: PROG [--foo FOO] spam
3574 '''
3575 help = usage + '''\
3576
3577 positional arguments:
3578 spam spam help
3579
3580 optional arguments:
3581 --foo FOO foo help
3582 '''
3583 version = ''
3584
3585
3586class TestHelpVersionOptional(HelpTestCase):
3587 """Test that the --version argument can be suppressed help messages"""
3588
3589 parser_signature = Sig(prog='PROG', version='1.0')
3590 argument_signatures = [
3591 Sig('--foo', help='foo help'),
3592 Sig('spam', help='spam help'),
3593 ]
3594 argument_group_signatures = []
3595 usage = '''\
3596 usage: PROG [-h] [-v] [--foo FOO] spam
3597 '''
3598 help = usage + '''\
3599
3600 positional arguments:
3601 spam spam help
3602
3603 optional arguments:
3604 -h, --help show this help message and exit
3605 -v, --version show program's version number and exit
3606 --foo FOO foo help
3607 '''
3608 version = '''\
3609 1.0
3610 '''
3611
3612
3613class TestHelpNone(HelpTestCase):
3614 """Test that no errors occur if no help is specified"""
3615
3616 parser_signature = Sig(prog='PROG')
3617 argument_signatures = [
3618 Sig('--foo'),
3619 Sig('spam'),
3620 ]
3621 argument_group_signatures = []
3622 usage = '''\
3623 usage: PROG [-h] [--foo FOO] spam
3624 '''
3625 help = usage + '''\
3626
3627 positional arguments:
3628 spam
3629
3630 optional arguments:
3631 -h, --help show this help message and exit
3632 --foo FOO
3633 '''
3634 version = ''
3635
3636
3637class TestHelpTupleMetavar(HelpTestCase):
3638 """Test specifying metavar as a tuple"""
3639
3640 parser_signature = Sig(prog='PROG')
3641 argument_signatures = [
3642 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3643 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3644 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3645 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3646 ]
3647 argument_group_signatures = []
3648 usage = '''\
3649 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3650[-z [Z1]]
3651 '''
3652 help = usage + '''\
3653
3654 optional arguments:
3655 -h, --help show this help message and exit
3656 -w W1 [W2 ...] w
3657 -x [X1 [X2 ...]] x
3658 -y Y1 Y2 Y3 y
3659 -z [Z1] z
3660 '''
3661 version = ''
3662
3663
3664class TestHelpRawText(HelpTestCase):
3665 """Test the RawTextHelpFormatter"""
3666
3667 parser_signature = Sig(
3668 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3669 description='Keep the formatting\n'
3670 ' exactly as it is written\n'
3671 '\n'
3672 'here\n')
3673
3674 argument_signatures = [
3675 Sig('--foo', help=' foo help should also\n'
3676 'appear as given here'),
3677 Sig('spam', help='spam help'),
3678 ]
3679 argument_group_signatures = [
3680 (Sig('title', description=' This text\n'
3681 ' should be indented\n'
3682 ' exactly like it is here\n'),
3683 [Sig('--bar', help='bar help')]),
3684 ]
3685 usage = '''\
3686 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3687 '''
3688 help = usage + '''\
3689
3690 Keep the formatting
3691 exactly as it is written
3692
3693 here
3694
3695 positional arguments:
3696 spam spam help
3697
3698 optional arguments:
3699 -h, --help show this help message and exit
3700 --foo FOO foo help should also
3701 appear as given here
3702
3703 title:
3704 This text
3705 should be indented
3706 exactly like it is here
3707
3708 --bar BAR bar help
3709 '''
3710 version = ''
3711
3712
3713class TestHelpRawDescription(HelpTestCase):
3714 """Test the RawTextHelpFormatter"""
3715
3716 parser_signature = Sig(
3717 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3718 description='Keep the formatting\n'
3719 ' exactly as it is written\n'
3720 '\n'
3721 'here\n')
3722
3723 argument_signatures = [
3724 Sig('--foo', help=' foo help should not\n'
3725 ' retain this odd formatting'),
3726 Sig('spam', help='spam help'),
3727 ]
3728 argument_group_signatures = [
3729 (Sig('title', description=' This text\n'
3730 ' should be indented\n'
3731 ' exactly like it is here\n'),
3732 [Sig('--bar', help='bar help')]),
3733 ]
3734 usage = '''\
3735 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3736 '''
3737 help = usage + '''\
3738
3739 Keep the formatting
3740 exactly as it is written
3741
3742 here
3743
3744 positional arguments:
3745 spam spam help
3746
3747 optional arguments:
3748 -h, --help show this help message and exit
3749 --foo FOO foo help should not retain this odd formatting
3750
3751 title:
3752 This text
3753 should be indented
3754 exactly like it is here
3755
3756 --bar BAR bar help
3757 '''
3758 version = ''
3759
3760
3761class TestHelpArgumentDefaults(HelpTestCase):
3762 """Test the ArgumentDefaultsHelpFormatter"""
3763
3764 parser_signature = Sig(
3765 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3766 description='description')
3767
3768 argument_signatures = [
3769 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3770 Sig('--bar', action='store_true', help='bar help'),
3771 Sig('spam', help='spam help'),
3772 Sig('badger', nargs='?', default='wooden', help='badger help'),
3773 ]
3774 argument_group_signatures = [
3775 (Sig('title', description='description'),
3776 [Sig('--baz', type=int, default=42, help='baz help')]),
3777 ]
3778 usage = '''\
3779 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3780 '''
3781 help = usage + '''\
3782
3783 description
3784
3785 positional arguments:
3786 spam spam help
3787 badger badger help (default: wooden)
3788
3789 optional arguments:
3790 -h, --help show this help message and exit
3791 --foo FOO foo help - oh and by the way, None
3792 --bar bar help (default: False)
3793
3794 title:
3795 description
3796
3797 --baz BAZ baz help (default: 42)
3798 '''
3799 version = ''
3800
Steven Betharddce6e1b2010-05-24 03:45:26 +00003801class TestHelpVersionAction(HelpTestCase):
3802 """Test the default help for the version action"""
3803
3804 parser_signature = Sig(prog='PROG', description='description')
3805 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3806 argument_group_signatures = []
3807 usage = '''\
3808 usage: PROG [-h] [-V]
3809 '''
3810 help = usage + '''\
3811
3812 description
3813
3814 optional arguments:
3815 -h, --help show this help message and exit
3816 -V, --version show program's version number and exit
3817 '''
3818 version = ''
3819
Benjamin Petersona39e9662010-03-02 22:05:59 +00003820# =====================================
3821# Optional/Positional constructor tests
3822# =====================================
3823
3824class TestInvalidArgumentConstructors(TestCase):
3825 """Test a bunch of invalid Argument constructors"""
3826
3827 def assertTypeError(self, *args, **kwargs):
3828 parser = argparse.ArgumentParser()
3829 self.assertRaises(TypeError, parser.add_argument,
3830 *args, **kwargs)
3831
3832 def assertValueError(self, *args, **kwargs):
3833 parser = argparse.ArgumentParser()
3834 self.assertRaises(ValueError, parser.add_argument,
3835 *args, **kwargs)
3836
3837 def test_invalid_keyword_arguments(self):
3838 self.assertTypeError('-x', bar=None)
3839 self.assertTypeError('-y', callback='foo')
3840 self.assertTypeError('-y', callback_args=())
3841 self.assertTypeError('-y', callback_kwargs={})
3842
3843 def test_missing_destination(self):
3844 self.assertTypeError()
3845 for action in ['append', 'store']:
3846 self.assertTypeError(action=action)
3847
3848 def test_invalid_option_strings(self):
3849 self.assertValueError('--')
3850 self.assertValueError('---')
3851
3852 def test_invalid_type(self):
3853 self.assertValueError('--foo', type='int')
3854
3855 def test_invalid_action(self):
3856 self.assertValueError('-x', action='foo')
3857 self.assertValueError('foo', action='baz')
3858 parser = argparse.ArgumentParser()
3859 try:
3860 parser.add_argument("--foo", action="store-true")
3861 except ValueError:
3862 e = sys.exc_info()[1]
3863 expected = 'unknown action'
3864 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00003865 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00003866
3867 def test_multiple_dest(self):
3868 parser = argparse.ArgumentParser()
3869 parser.add_argument(dest='foo')
3870 try:
3871 parser.add_argument('bar', dest='baz')
3872 except ValueError:
3873 e = sys.exc_info()[1]
3874 expected = 'dest supplied twice for positional argument'
3875 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00003876 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00003877
3878 def test_no_argument_actions(self):
3879 for action in ['store_const', 'store_true', 'store_false',
3880 'append_const', 'count']:
3881 for attrs in [dict(type=int), dict(nargs='+'),
3882 dict(choices='ab')]:
3883 self.assertTypeError('-x', action=action, **attrs)
3884
3885 def test_no_argument_no_const_actions(self):
3886 # options with zero arguments
3887 for action in ['store_true', 'store_false', 'count']:
3888
3889 # const is always disallowed
3890 self.assertTypeError('-x', const='foo', action=action)
3891
3892 # nargs is always disallowed
3893 self.assertTypeError('-x', nargs='*', action=action)
3894
3895 def test_more_than_one_argument_actions(self):
3896 for action in ['store', 'append']:
3897
3898 # nargs=0 is disallowed
3899 self.assertValueError('-x', nargs=0, action=action)
3900 self.assertValueError('spam', nargs=0, action=action)
3901
3902 # const is disallowed with non-optional arguments
3903 for nargs in [1, '*', '+']:
3904 self.assertValueError('-x', const='foo',
3905 nargs=nargs, action=action)
3906 self.assertValueError('spam', const='foo',
3907 nargs=nargs, action=action)
3908
3909 def test_required_const_actions(self):
3910 for action in ['store_const', 'append_const']:
3911
3912 # nargs is always disallowed
3913 self.assertTypeError('-x', nargs='+', action=action)
3914
3915 def test_parsers_action_missing_params(self):
3916 self.assertTypeError('command', action='parsers')
3917 self.assertTypeError('command', action='parsers', prog='PROG')
3918 self.assertTypeError('command', action='parsers',
3919 parser_class=argparse.ArgumentParser)
3920
3921 def test_required_positional(self):
3922 self.assertTypeError('foo', required=True)
3923
3924 def test_user_defined_action(self):
3925
3926 class Success(Exception):
3927 pass
3928
3929 class Action(object):
3930
3931 def __init__(self,
3932 option_strings,
3933 dest,
3934 const,
3935 default,
3936 required=False):
3937 if dest == 'spam':
3938 if const is Success:
3939 if default is Success:
3940 raise Success()
3941
3942 def __call__(self, *args, **kwargs):
3943 pass
3944
3945 parser = argparse.ArgumentParser()
3946 self.assertRaises(Success, parser.add_argument, '--spam',
3947 action=Action, default=Success, const=Success)
3948 self.assertRaises(Success, parser.add_argument, 'spam',
3949 action=Action, default=Success, const=Success)
3950
3951# ================================
3952# Actions returned by add_argument
3953# ================================
3954
3955class TestActionsReturned(TestCase):
3956
3957 def test_dest(self):
3958 parser = argparse.ArgumentParser()
3959 action = parser.add_argument('--foo')
3960 self.assertEqual(action.dest, 'foo')
3961 action = parser.add_argument('-b', '--bar')
3962 self.assertEqual(action.dest, 'bar')
3963 action = parser.add_argument('-x', '-y')
3964 self.assertEqual(action.dest, 'x')
3965
3966 def test_misc(self):
3967 parser = argparse.ArgumentParser()
3968 action = parser.add_argument('--foo', nargs='?', const=42,
3969 default=84, type=int, choices=[1, 2],
3970 help='FOO', metavar='BAR', dest='baz')
3971 self.assertEqual(action.nargs, '?')
3972 self.assertEqual(action.const, 42)
3973 self.assertEqual(action.default, 84)
3974 self.assertEqual(action.type, int)
3975 self.assertEqual(action.choices, [1, 2])
3976 self.assertEqual(action.help, 'FOO')
3977 self.assertEqual(action.metavar, 'BAR')
3978 self.assertEqual(action.dest, 'baz')
3979
3980
3981# ================================
3982# Argument conflict handling tests
3983# ================================
3984
3985class TestConflictHandling(TestCase):
3986
3987 def test_bad_type(self):
3988 self.assertRaises(ValueError, argparse.ArgumentParser,
3989 conflict_handler='foo')
3990
3991 def test_conflict_error(self):
3992 parser = argparse.ArgumentParser()
3993 parser.add_argument('-x')
3994 self.assertRaises(argparse.ArgumentError,
3995 parser.add_argument, '-x')
3996 parser.add_argument('--spam')
3997 self.assertRaises(argparse.ArgumentError,
3998 parser.add_argument, '--spam')
3999
4000 def test_resolve_error(self):
4001 get_parser = argparse.ArgumentParser
4002 parser = get_parser(prog='PROG', conflict_handler='resolve')
4003
4004 parser.add_argument('-x', help='OLD X')
4005 parser.add_argument('-x', help='NEW X')
4006 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4007 usage: PROG [-h] [-x X]
4008
4009 optional arguments:
4010 -h, --help show this help message and exit
4011 -x X NEW X
4012 '''))
4013
4014 parser.add_argument('--spam', metavar='OLD_SPAM')
4015 parser.add_argument('--spam', metavar='NEW_SPAM')
4016 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4017 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4018
4019 optional arguments:
4020 -h, --help show this help message and exit
4021 -x X NEW X
4022 --spam NEW_SPAM
4023 '''))
4024
4025
4026# =============================
4027# Help and Version option tests
4028# =============================
4029
4030class TestOptionalsHelpVersionActions(TestCase):
4031 """Test the help and version actions"""
4032
4033 def _get_error(self, func, *args, **kwargs):
4034 try:
4035 func(*args, **kwargs)
4036 except ArgumentParserError:
4037 return sys.exc_info()[1]
4038 else:
4039 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4040
4041 def assertPrintHelpExit(self, parser, args_str):
4042 self.assertEqual(
4043 parser.format_help(),
4044 self._get_error(parser.parse_args, args_str.split()).stdout)
4045
4046 def assertPrintVersionExit(self, parser, args_str):
4047 self.assertEqual(
4048 parser.format_version(),
4049 self._get_error(parser.parse_args, args_str.split()).stderr)
4050
4051 def assertArgumentParserError(self, parser, *args):
4052 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4053
4054 def test_version(self):
4055 parser = ErrorRaisingArgumentParser(version='1.0')
4056 self.assertPrintHelpExit(parser, '-h')
4057 self.assertPrintHelpExit(parser, '--help')
4058 self.assertPrintVersionExit(parser, '-v')
4059 self.assertPrintVersionExit(parser, '--version')
4060
4061 def test_version_format(self):
4062 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4063 msg = self._get_error(parser.parse_args, ['-v']).stderr
4064 self.assertEqual('PPP 3.5\n', msg)
4065
4066 def test_version_no_help(self):
4067 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4068 self.assertArgumentParserError(parser, '-h')
4069 self.assertArgumentParserError(parser, '--help')
4070 self.assertPrintVersionExit(parser, '-v')
4071 self.assertPrintVersionExit(parser, '--version')
4072
4073 def test_version_action(self):
4074 parser = ErrorRaisingArgumentParser(prog='XXX')
4075 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4076 msg = self._get_error(parser.parse_args, ['-V']).stderr
4077 self.assertEqual('XXX 3.7\n', msg)
4078
4079 def test_no_help(self):
4080 parser = ErrorRaisingArgumentParser(add_help=False)
4081 self.assertArgumentParserError(parser, '-h')
4082 self.assertArgumentParserError(parser, '--help')
4083 self.assertArgumentParserError(parser, '-v')
4084 self.assertArgumentParserError(parser, '--version')
4085
4086 def test_alternate_help_version(self):
4087 parser = ErrorRaisingArgumentParser()
4088 parser.add_argument('-x', action='help')
4089 parser.add_argument('-y', action='version')
4090 self.assertPrintHelpExit(parser, '-x')
4091 self.assertPrintVersionExit(parser, '-y')
4092 self.assertArgumentParserError(parser, '-v')
4093 self.assertArgumentParserError(parser, '--version')
4094
4095 def test_help_version_extra_arguments(self):
4096 parser = ErrorRaisingArgumentParser(version='1.0')
4097 parser.add_argument('-x', action='store_true')
4098 parser.add_argument('y')
4099
4100 # try all combinations of valid prefixes and suffixes
4101 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4102 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4103 for prefix in valid_prefixes:
4104 for suffix in valid_suffixes:
4105 format = '%s %%s %s' % (prefix, suffix)
4106 self.assertPrintHelpExit(parser, format % '-h')
4107 self.assertPrintHelpExit(parser, format % '--help')
4108 self.assertPrintVersionExit(parser, format % '-v')
4109 self.assertPrintVersionExit(parser, format % '--version')
4110
4111
4112# ======================
4113# str() and repr() tests
4114# ======================
4115
4116class TestStrings(TestCase):
4117 """Test str() and repr() on Optionals and Positionals"""
4118
4119 def assertStringEqual(self, obj, result_string):
4120 for func in [str, repr]:
4121 self.assertEqual(func(obj), result_string)
4122
4123 def test_optional(self):
4124 option = argparse.Action(
4125 option_strings=['--foo', '-a', '-b'],
4126 dest='b',
4127 type='int',
4128 nargs='+',
4129 default=42,
4130 choices=[1, 2, 3],
4131 help='HELP',
4132 metavar='METAVAR')
4133 string = (
4134 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4135 "nargs='+', const=None, default=42, type='int', "
4136 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4137 self.assertStringEqual(option, string)
4138
4139 def test_argument(self):
4140 argument = argparse.Action(
4141 option_strings=[],
4142 dest='x',
4143 type=float,
4144 nargs='?',
4145 default=2.5,
4146 choices=[0.5, 1.5, 2.5],
4147 help='H HH H',
4148 metavar='MV MV MV')
4149 string = (
4150 "Action(option_strings=[], dest='x', nargs='?', "
4151 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4152 "help='H HH H', metavar='MV MV MV')" % float)
4153 self.assertStringEqual(argument, string)
4154
4155 def test_namespace(self):
4156 ns = argparse.Namespace(foo=42, bar='spam')
4157 string = "Namespace(bar='spam', foo=42)"
4158 self.assertStringEqual(ns, string)
4159
4160 def test_parser(self):
4161 parser = argparse.ArgumentParser(prog='PROG')
4162 string = (
4163 "ArgumentParser(prog='PROG', usage=None, description=None, "
4164 "version=None, formatter_class=%r, conflict_handler='error', "
4165 "add_help=True)" % argparse.HelpFormatter)
4166 self.assertStringEqual(parser, string)
4167
4168# ===============
4169# Namespace tests
4170# ===============
4171
4172class TestNamespace(TestCase):
4173
4174 def test_constructor(self):
4175 ns = argparse.Namespace()
4176 self.assertRaises(AttributeError, getattr, ns, 'x')
4177
4178 ns = argparse.Namespace(a=42, b='spam')
4179 self.assertEqual(ns.a, 42)
4180 self.assertEqual(ns.b, 'spam')
4181
4182 def test_equality(self):
4183 ns1 = argparse.Namespace(a=1, b=2)
4184 ns2 = argparse.Namespace(b=2, a=1)
4185 ns3 = argparse.Namespace(a=1)
4186 ns4 = argparse.Namespace(b=2)
4187
4188 self.assertEqual(ns1, ns2)
4189 self.assertNotEqual(ns1, ns3)
4190 self.assertNotEqual(ns1, ns4)
4191 self.assertNotEqual(ns2, ns3)
4192 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004193 self.assertTrue(ns1 != ns3)
4194 self.assertTrue(ns1 != ns4)
4195 self.assertTrue(ns2 != ns3)
4196 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004197
4198
4199# ===================
4200# File encoding tests
4201# ===================
4202
4203class TestEncoding(TestCase):
4204
4205 def _test_module_encoding(self, path):
4206 path, _ = os.path.splitext(path)
4207 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004208 with codecs.open(path, 'r', 'utf8') as f:
4209 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004210
4211 def test_argparse_module_encoding(self):
4212 self._test_module_encoding(argparse.__file__)
4213
4214 def test_test_argparse_module_encoding(self):
4215 self._test_module_encoding(__file__)
4216
4217# ===================
4218# ArgumentError tests
4219# ===================
4220
4221class TestArgumentError(TestCase):
4222
4223 def test_argument_error(self):
4224 msg = "my error here"
4225 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004226 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004227
4228# =======================
4229# ArgumentTypeError tests
4230# =======================
4231
4232class TestArgumentError(TestCase):
4233
4234 def test_argument_type_error(self):
4235
4236 def spam(string):
4237 raise argparse.ArgumentTypeError('spam!')
4238
4239 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4240 parser.add_argument('x', type=spam)
4241 try:
4242 parser.parse_args(['XXX'])
4243 except ArgumentParserError:
4244 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4245 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004246 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004247 else:
4248 self.fail()
4249
4250# ======================
4251# parse_known_args tests
4252# ======================
4253
4254class TestParseKnownArgs(TestCase):
4255
4256 def test_optionals(self):
4257 parser = argparse.ArgumentParser()
4258 parser.add_argument('--foo')
4259 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004260 self.assertEqual(NS(foo='F'), args)
4261 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004262
4263 def test_mixed(self):
4264 parser = argparse.ArgumentParser()
4265 parser.add_argument('-v', nargs='?', const=1, type=int)
4266 parser.add_argument('--spam', action='store_false')
4267 parser.add_argument('badger')
4268
4269 argv = ["B", "C", "--foo", "-v", "3", "4"]
4270 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004271 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4272 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004273
4274# ============================
4275# from argparse import * tests
4276# ============================
4277
4278class TestImportStar(TestCase):
4279
4280 def test(self):
4281 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004282 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004283
Steven Bethard931906a2010-11-01 15:24:42 +00004284 def test_all_exports_everything_but_modules(self):
4285 items = [
4286 name
4287 for name, value in vars(argparse).items()
4288 if not name.startswith("_")
4289 if not inspect.ismodule(value)
4290 ]
4291 self.assertEqual(sorted(items), sorted(argparse.__all__))
4292
Benjamin Peterson036fae32010-03-02 22:20:10 +00004293def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004294 # silence warnings about version argument - these are expected
4295 with test_support.check_warnings(
4296 ('The "version" argument to ArgumentParser is deprecated.',
4297 DeprecationWarning),
4298 ('The (format|print)_version method is deprecated',
4299 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004300 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004301 # Remove global references to avoid looking like we have refleaks.
4302 RFile.seen = {}
4303 WFile.seen = set()
4304
Benjamin Peterson036fae32010-03-02 22:20:10 +00004305
Benjamin Petersona39e9662010-03-02 22:05:59 +00004306
4307if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004308 test_main()