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