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