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