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