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