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