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