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