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