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