1# 2# Test suite for Optik. Supplied by Johannes Gijsbers 3# (taradino@softhome.net) -- translated from the original Optik 4# test suite to this PyUnit-based version. 5# 6# $Id$ 7# 8 9import sys 10import os 11import re 12import copy 13import unittest 14 15from io import StringIO 16from test import support 17from test.support import os_helper 18 19 20import optparse 21from optparse import make_option, Option, \ 22 TitledHelpFormatter, OptionParser, OptionGroup, \ 23 SUPPRESS_USAGE, OptionError, OptionConflictError, \ 24 BadOptionError, OptionValueError, Values 25from optparse import _match_abbrev 26from optparse import _parse_num 27 28class InterceptedError(Exception): 29 def __init__(self, 30 error_message=None, 31 exit_status=None, 32 exit_message=None): 33 self.error_message = error_message 34 self.exit_status = exit_status 35 self.exit_message = exit_message 36 37 def __str__(self): 38 return self.error_message or self.exit_message or "intercepted error" 39 40class InterceptingOptionParser(OptionParser): 41 def exit(self, status=0, msg=None): 42 raise InterceptedError(exit_status=status, exit_message=msg) 43 44 def error(self, msg): 45 raise InterceptedError(error_message=msg) 46 47 48class BaseTest(unittest.TestCase): 49 def assertParseOK(self, args, expected_opts, expected_positional_args): 50 """Assert the options are what we expected when parsing arguments. 51 52 Otherwise, fail with a nicely formatted message. 53 54 Keyword arguments: 55 args -- A list of arguments to parse with OptionParser. 56 expected_opts -- The options expected. 57 expected_positional_args -- The positional arguments expected. 58 59 Returns the options and positional args for further testing. 60 """ 61 62 (options, positional_args) = self.parser.parse_args(args) 63 optdict = vars(options) 64 65 self.assertEqual(optdict, expected_opts, 66 """ 67Options are %(optdict)s. 68Should be %(expected_opts)s. 69Args were %(args)s.""" % locals()) 70 71 self.assertEqual(positional_args, expected_positional_args, 72 """ 73Positional arguments are %(positional_args)s. 74Should be %(expected_positional_args)s. 75Args were %(args)s.""" % locals ()) 76 77 return (options, positional_args) 78 79 def assertRaises(self, 80 func, 81 args, 82 kwargs, 83 expected_exception, 84 expected_message): 85 """ 86 Assert that the expected exception is raised when calling a 87 function, and that the right error message is included with 88 that exception. 89 90 Arguments: 91 func -- the function to call 92 args -- positional arguments to `func` 93 kwargs -- keyword arguments to `func` 94 expected_exception -- exception that should be raised 95 expected_message -- expected exception message (or pattern 96 if a compiled regex object) 97 98 Returns the exception raised for further testing. 99 """ 100 if args is None: 101 args = () 102 if kwargs is None: 103 kwargs = {} 104 105 try: 106 func(*args, **kwargs) 107 except expected_exception as err: 108 actual_message = str(err) 109 if isinstance(expected_message, re.Pattern): 110 self.assertTrue(expected_message.search(actual_message), 111 """\ 112expected exception message pattern: 113/%s/ 114actual exception message: 115'''%s''' 116""" % (expected_message.pattern, actual_message)) 117 else: 118 self.assertEqual(actual_message, 119 expected_message, 120 """\ 121expected exception message: 122'''%s''' 123actual exception message: 124'''%s''' 125""" % (expected_message, actual_message)) 126 127 return err 128 else: 129 self.fail("""expected exception %(expected_exception)s not raised 130called %(func)r 131with args %(args)r 132and kwargs %(kwargs)r 133""" % locals ()) 134 135 136 # -- Assertions used in more than one class -------------------- 137 138 def assertParseFail(self, cmdline_args, expected_output): 139 """ 140 Assert the parser fails with the expected message. Caller 141 must ensure that self.parser is an InterceptingOptionParser. 142 """ 143 try: 144 self.parser.parse_args(cmdline_args) 145 except InterceptedError as err: 146 self.assertEqual(err.error_message, expected_output) 147 else: 148 self.assertFalse("expected parse failure") 149 150 def assertOutput(self, 151 cmdline_args, 152 expected_output, 153 expected_status=0, 154 expected_error=None): 155 """Assert the parser prints the expected output on stdout.""" 156 save_stdout = sys.stdout 157 try: 158 try: 159 sys.stdout = StringIO() 160 self.parser.parse_args(cmdline_args) 161 finally: 162 output = sys.stdout.getvalue() 163 sys.stdout = save_stdout 164 165 except InterceptedError as err: 166 self.assertTrue( 167 isinstance(output, str), 168 "expected output to be an ordinary string, not %r" 169 % type(output)) 170 171 if output != expected_output: 172 self.fail("expected: \n'''\n" + expected_output + 173 "'''\nbut got \n'''\n" + output + "'''") 174 self.assertEqual(err.exit_status, expected_status) 175 self.assertEqual(err.exit_message, expected_error) 176 else: 177 self.assertFalse("expected parser.exit()") 178 179 def assertTypeError(self, func, expected_message, *args): 180 """Assert that TypeError is raised when executing func.""" 181 self.assertRaises(func, args, None, TypeError, expected_message) 182 183 def assertHelp(self, parser, expected_help): 184 actual_help = parser.format_help() 185 if actual_help != expected_help: 186 raise self.failureException( 187 'help text failure; expected:\n"' + 188 expected_help + '"; got:\n"' + 189 actual_help + '"\n') 190 191# -- Test make_option() aka Option ------------------------------------- 192 193# It's not necessary to test correct options here. All the tests in the 194# parser.parse_args() section deal with those, because they're needed 195# there. 196 197class TestOptionChecks(BaseTest): 198 def setUp(self): 199 self.parser = OptionParser(usage=SUPPRESS_USAGE) 200 201 def assertOptionError(self, expected_message, args=[], kwargs={}): 202 self.assertRaises(make_option, args, kwargs, 203 OptionError, expected_message) 204 205 def test_opt_string_empty(self): 206 self.assertTypeError(make_option, 207 "at least one option string must be supplied") 208 209 def test_opt_string_too_short(self): 210 self.assertOptionError( 211 "invalid option string 'b': must be at least two characters long", 212 ["b"]) 213 214 def test_opt_string_short_invalid(self): 215 self.assertOptionError( 216 "invalid short option string '--': must be " 217 "of the form -x, (x any non-dash char)", 218 ["--"]) 219 220 def test_opt_string_long_invalid(self): 221 self.assertOptionError( 222 "invalid long option string '---': " 223 "must start with --, followed by non-dash", 224 ["---"]) 225 226 def test_attr_invalid(self): 227 self.assertOptionError( 228 "option -b: invalid keyword arguments: bar, foo", 229 ["-b"], {'foo': None, 'bar': None}) 230 231 def test_action_invalid(self): 232 self.assertOptionError( 233 "option -b: invalid action: 'foo'", 234 ["-b"], {'action': 'foo'}) 235 236 def test_type_invalid(self): 237 self.assertOptionError( 238 "option -b: invalid option type: 'foo'", 239 ["-b"], {'type': 'foo'}) 240 self.assertOptionError( 241 "option -b: invalid option type: 'tuple'", 242 ["-b"], {'type': tuple}) 243 244 def test_no_type_for_action(self): 245 self.assertOptionError( 246 "option -b: must not supply a type for action 'count'", 247 ["-b"], {'action': 'count', 'type': 'int'}) 248 249 def test_no_choices_list(self): 250 self.assertOptionError( 251 "option -b/--bad: must supply a list of " 252 "choices for type 'choice'", 253 ["-b", "--bad"], {'type': "choice"}) 254 255 def test_bad_choices_list(self): 256 typename = type('').__name__ 257 self.assertOptionError( 258 "option -b/--bad: choices must be a list of " 259 "strings ('%s' supplied)" % typename, 260 ["-b", "--bad"], 261 {'type': "choice", 'choices':"bad choices"}) 262 263 def test_no_choices_for_type(self): 264 self.assertOptionError( 265 "option -b: must not supply choices for type 'int'", 266 ["-b"], {'type': 'int', 'choices':"bad"}) 267 268 def test_no_const_for_action(self): 269 self.assertOptionError( 270 "option -b: 'const' must not be supplied for action 'store'", 271 ["-b"], {'action': 'store', 'const': 1}) 272 273 def test_no_nargs_for_action(self): 274 self.assertOptionError( 275 "option -b: 'nargs' must not be supplied for action 'count'", 276 ["-b"], {'action': 'count', 'nargs': 2}) 277 278 def test_callback_not_callable(self): 279 self.assertOptionError( 280 "option -b: callback not callable: 'foo'", 281 ["-b"], {'action': 'callback', 282 'callback': 'foo'}) 283 284 def dummy(self): 285 pass 286 287 def test_callback_args_no_tuple(self): 288 self.assertOptionError( 289 "option -b: callback_args, if supplied, " 290 "must be a tuple: not 'foo'", 291 ["-b"], {'action': 'callback', 292 'callback': self.dummy, 293 'callback_args': 'foo'}) 294 295 def test_callback_kwargs_no_dict(self): 296 self.assertOptionError( 297 "option -b: callback_kwargs, if supplied, " 298 "must be a dict: not 'foo'", 299 ["-b"], {'action': 'callback', 300 'callback': self.dummy, 301 'callback_kwargs': 'foo'}) 302 303 def test_no_callback_for_action(self): 304 self.assertOptionError( 305 "option -b: callback supplied ('foo') for non-callback option", 306 ["-b"], {'action': 'store', 307 'callback': 'foo'}) 308 309 def test_no_callback_args_for_action(self): 310 self.assertOptionError( 311 "option -b: callback_args supplied for non-callback option", 312 ["-b"], {'action': 'store', 313 'callback_args': 'foo'}) 314 315 def test_no_callback_kwargs_for_action(self): 316 self.assertOptionError( 317 "option -b: callback_kwargs supplied for non-callback option", 318 ["-b"], {'action': 'store', 319 'callback_kwargs': 'foo'}) 320 321 def test_no_single_dash(self): 322 self.assertOptionError( 323 "invalid long option string '-debug': " 324 "must start with --, followed by non-dash", 325 ["-debug"]) 326 327 self.assertOptionError( 328 "option -d: invalid long option string '-debug': must start with" 329 " --, followed by non-dash", 330 ["-d", "-debug"]) 331 332 self.assertOptionError( 333 "invalid long option string '-debug': " 334 "must start with --, followed by non-dash", 335 ["-debug", "--debug"]) 336 337class TestOptionParser(BaseTest): 338 def setUp(self): 339 self.parser = OptionParser() 340 self.parser.add_option("-v", "--verbose", "-n", "--noisy", 341 action="store_true", dest="verbose") 342 self.parser.add_option("-q", "--quiet", "--silent", 343 action="store_false", dest="verbose") 344 345 def test_add_option_no_Option(self): 346 self.assertTypeError(self.parser.add_option, 347 "not an Option instance: None", None) 348 349 def test_add_option_invalid_arguments(self): 350 self.assertTypeError(self.parser.add_option, 351 "invalid arguments", None, None) 352 353 def test_get_option(self): 354 opt1 = self.parser.get_option("-v") 355 self.assertIsInstance(opt1, Option) 356 self.assertEqual(opt1._short_opts, ["-v", "-n"]) 357 self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"]) 358 self.assertEqual(opt1.action, "store_true") 359 self.assertEqual(opt1.dest, "verbose") 360 361 def test_get_option_equals(self): 362 opt1 = self.parser.get_option("-v") 363 opt2 = self.parser.get_option("--verbose") 364 opt3 = self.parser.get_option("-n") 365 opt4 = self.parser.get_option("--noisy") 366 self.assertTrue(opt1 is opt2 is opt3 is opt4) 367 368 def test_has_option(self): 369 self.assertTrue(self.parser.has_option("-v")) 370 self.assertTrue(self.parser.has_option("--verbose")) 371 372 def assertTrueremoved(self): 373 self.assertTrue(self.parser.get_option("-v") is None) 374 self.assertTrue(self.parser.get_option("--verbose") is None) 375 self.assertTrue(self.parser.get_option("-n") is None) 376 self.assertTrue(self.parser.get_option("--noisy") is None) 377 378 self.assertFalse(self.parser.has_option("-v")) 379 self.assertFalse(self.parser.has_option("--verbose")) 380 self.assertFalse(self.parser.has_option("-n")) 381 self.assertFalse(self.parser.has_option("--noisy")) 382 383 self.assertTrue(self.parser.has_option("-q")) 384 self.assertTrue(self.parser.has_option("--silent")) 385 386 def test_remove_short_opt(self): 387 self.parser.remove_option("-n") 388 self.assertTrueremoved() 389 390 def test_remove_long_opt(self): 391 self.parser.remove_option("--verbose") 392 self.assertTrueremoved() 393 394 def test_remove_nonexistent(self): 395 self.assertRaises(self.parser.remove_option, ('foo',), None, 396 ValueError, "no such option 'foo'") 397 398 @support.impl_detail('Relies on sys.getrefcount', cpython=True) 399 def test_refleak(self): 400 # If an OptionParser is carrying around a reference to a large 401 # object, various cycles can prevent it from being GC'd in 402 # a timely fashion. destroy() breaks the cycles to ensure stuff 403 # can be cleaned up. 404 big_thing = [42] 405 refcount = sys.getrefcount(big_thing) 406 parser = OptionParser() 407 parser.add_option("-a", "--aaarggh") 408 parser.big_thing = big_thing 409 410 parser.destroy() 411 #self.assertEqual(refcount, sys.getrefcount(big_thing)) 412 del parser 413 self.assertEqual(refcount, sys.getrefcount(big_thing)) 414 415 416class TestOptionValues(BaseTest): 417 def setUp(self): 418 pass 419 420 def test_basics(self): 421 values = Values() 422 self.assertEqual(vars(values), {}) 423 self.assertEqual(values, {}) 424 self.assertNotEqual(values, {"foo": "bar"}) 425 self.assertNotEqual(values, "") 426 427 dict = {"foo": "bar", "baz": 42} 428 values = Values(defaults=dict) 429 self.assertEqual(vars(values), dict) 430 self.assertEqual(values, dict) 431 self.assertNotEqual(values, {"foo": "bar"}) 432 self.assertNotEqual(values, {}) 433 self.assertNotEqual(values, "") 434 self.assertNotEqual(values, []) 435 436 437class TestTypeAliases(BaseTest): 438 def setUp(self): 439 self.parser = OptionParser() 440 441 def test_str_aliases_string(self): 442 self.parser.add_option("-s", type="str") 443 self.assertEqual(self.parser.get_option("-s").type, "string") 444 445 def test_type_object(self): 446 self.parser.add_option("-s", type=str) 447 self.assertEqual(self.parser.get_option("-s").type, "string") 448 self.parser.add_option("-x", type=int) 449 self.assertEqual(self.parser.get_option("-x").type, "int") 450 451 452# Custom type for testing processing of default values. 453_time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 } 454 455def _check_duration(option, opt, value): 456 try: 457 if value[-1].isdigit(): 458 return int(value) 459 else: 460 return int(value[:-1]) * _time_units[value[-1]] 461 except (ValueError, IndexError): 462 raise OptionValueError( 463 'option %s: invalid duration: %r' % (opt, value)) 464 465class DurationOption(Option): 466 TYPES = Option.TYPES + ('duration',) 467 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER) 468 TYPE_CHECKER['duration'] = _check_duration 469 470class TestDefaultValues(BaseTest): 471 def setUp(self): 472 self.parser = OptionParser() 473 self.parser.add_option("-v", "--verbose", default=True) 474 self.parser.add_option("-q", "--quiet", dest='verbose') 475 self.parser.add_option("-n", type="int", default=37) 476 self.parser.add_option("-m", type="int") 477 self.parser.add_option("-s", default="foo") 478 self.parser.add_option("-t") 479 self.parser.add_option("-u", default=None) 480 self.expected = { 'verbose': True, 481 'n': 37, 482 'm': None, 483 's': "foo", 484 't': None, 485 'u': None } 486 487 def test_basic_defaults(self): 488 self.assertEqual(self.parser.get_default_values(), self.expected) 489 490 def test_mixed_defaults_post(self): 491 self.parser.set_defaults(n=42, m=-100) 492 self.expected.update({'n': 42, 'm': -100}) 493 self.assertEqual(self.parser.get_default_values(), self.expected) 494 495 def test_mixed_defaults_pre(self): 496 self.parser.set_defaults(x="barf", y="blah") 497 self.parser.add_option("-x", default="frob") 498 self.parser.add_option("-y") 499 500 self.expected.update({'x': "frob", 'y': "blah"}) 501 self.assertEqual(self.parser.get_default_values(), self.expected) 502 503 self.parser.remove_option("-y") 504 self.parser.add_option("-y", default=None) 505 self.expected.update({'y': None}) 506 self.assertEqual(self.parser.get_default_values(), self.expected) 507 508 def test_process_default(self): 509 self.parser.option_class = DurationOption 510 self.parser.add_option("-d", type="duration", default=300) 511 self.parser.add_option("-e", type="duration", default="6m") 512 self.parser.set_defaults(n="42") 513 self.expected.update({'d': 300, 'e': 360, 'n': 42}) 514 self.assertEqual(self.parser.get_default_values(), self.expected) 515 516 self.parser.set_process_default_values(False) 517 self.expected.update({'d': 300, 'e': "6m", 'n': "42"}) 518 self.assertEqual(self.parser.get_default_values(), self.expected) 519 520 521class TestProgName(BaseTest): 522 """ 523 Test that %prog expands to the right thing in usage, version, 524 and help strings. 525 """ 526 527 def assertUsage(self, parser, expected_usage): 528 self.assertEqual(parser.get_usage(), expected_usage) 529 530 def assertVersion(self, parser, expected_version): 531 self.assertEqual(parser.get_version(), expected_version) 532 533 534 def test_default_progname(self): 535 # Make sure that program name taken from sys.argv[0] by default. 536 save_argv = sys.argv[:] 537 try: 538 sys.argv[0] = os.path.join("foo", "bar", "baz.py") 539 parser = OptionParser("%prog ...", version="%prog 1.2") 540 expected_usage = "Usage: baz.py ...\n" 541 self.assertUsage(parser, expected_usage) 542 self.assertVersion(parser, "baz.py 1.2") 543 self.assertHelp(parser, 544 expected_usage + "\n" + 545 "Options:\n" 546 " --version show program's version number and exit\n" 547 " -h, --help show this help message and exit\n") 548 finally: 549 sys.argv[:] = save_argv 550 551 def test_custom_progname(self): 552 parser = OptionParser(prog="thingy", 553 version="%prog 0.1", 554 usage="%prog arg arg") 555 parser.remove_option("-h") 556 parser.remove_option("--version") 557 expected_usage = "Usage: thingy arg arg\n" 558 self.assertUsage(parser, expected_usage) 559 self.assertVersion(parser, "thingy 0.1") 560 self.assertHelp(parser, expected_usage + "\n") 561 562 563class TestExpandDefaults(BaseTest): 564 def setUp(self): 565 self.parser = OptionParser(prog="test") 566 self.help_prefix = """\ 567Usage: test [options] 568 569Options: 570 -h, --help show this help message and exit 571""" 572 self.file_help = "read from FILE [default: %default]" 573 self.expected_help_file = self.help_prefix + \ 574 " -f FILE, --file=FILE read from FILE [default: foo.txt]\n" 575 self.expected_help_none = self.help_prefix + \ 576 " -f FILE, --file=FILE read from FILE [default: none]\n" 577 578 def test_option_default(self): 579 self.parser.add_option("-f", "--file", 580 default="foo.txt", 581 help=self.file_help) 582 self.assertHelp(self.parser, self.expected_help_file) 583 584 def test_parser_default_1(self): 585 self.parser.add_option("-f", "--file", 586 help=self.file_help) 587 self.parser.set_default('file', "foo.txt") 588 self.assertHelp(self.parser, self.expected_help_file) 589 590 def test_parser_default_2(self): 591 self.parser.add_option("-f", "--file", 592 help=self.file_help) 593 self.parser.set_defaults(file="foo.txt") 594 self.assertHelp(self.parser, self.expected_help_file) 595 596 def test_no_default(self): 597 self.parser.add_option("-f", "--file", 598 help=self.file_help) 599 self.assertHelp(self.parser, self.expected_help_none) 600 601 def test_default_none_1(self): 602 self.parser.add_option("-f", "--file", 603 default=None, 604 help=self.file_help) 605 self.assertHelp(self.parser, self.expected_help_none) 606 607 def test_default_none_2(self): 608 self.parser.add_option("-f", "--file", 609 help=self.file_help) 610 self.parser.set_defaults(file=None) 611 self.assertHelp(self.parser, self.expected_help_none) 612 613 def test_float_default(self): 614 self.parser.add_option( 615 "-p", "--prob", 616 help="blow up with probability PROB [default: %default]") 617 self.parser.set_defaults(prob=0.43) 618 expected_help = self.help_prefix + \ 619 " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n" 620 self.assertHelp(self.parser, expected_help) 621 622 def test_alt_expand(self): 623 self.parser.add_option("-f", "--file", 624 default="foo.txt", 625 help="read from FILE [default: *DEFAULT*]") 626 self.parser.formatter.default_tag = "*DEFAULT*" 627 self.assertHelp(self.parser, self.expected_help_file) 628 629 def test_no_expand(self): 630 self.parser.add_option("-f", "--file", 631 default="foo.txt", 632 help="read from %default file") 633 self.parser.formatter.default_tag = None 634 expected_help = self.help_prefix + \ 635 " -f FILE, --file=FILE read from %default file\n" 636 self.assertHelp(self.parser, expected_help) 637 638 639# -- Test parser.parse_args() ------------------------------------------ 640 641class TestStandard(BaseTest): 642 def setUp(self): 643 options = [make_option("-a", type="string"), 644 make_option("-b", "--boo", type="int", dest='boo'), 645 make_option("--foo", action="append")] 646 647 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 648 option_list=options) 649 650 def test_required_value(self): 651 self.assertParseFail(["-a"], "-a option requires 1 argument") 652 653 def test_invalid_integer(self): 654 self.assertParseFail(["-b", "5x"], 655 "option -b: invalid integer value: '5x'") 656 657 def test_no_such_option(self): 658 self.assertParseFail(["--boo13"], "no such option: --boo13") 659 660 def test_long_invalid_integer(self): 661 self.assertParseFail(["--boo=x5"], 662 "option --boo: invalid integer value: 'x5'") 663 664 def test_empty(self): 665 self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, []) 666 667 def test_shortopt_empty_longopt_append(self): 668 self.assertParseOK(["-a", "", "--foo=blah", "--foo="], 669 {'a': "", 'boo': None, 'foo': ["blah", ""]}, 670 []) 671 672 def test_long_option_append(self): 673 self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"], 674 {'a': None, 675 'boo': None, 676 'foo': ["bar", "", "x"]}, 677 []) 678 679 def test_option_argument_joined(self): 680 self.assertParseOK(["-abc"], 681 {'a': "bc", 'boo': None, 'foo': None}, 682 []) 683 684 def test_option_argument_split(self): 685 self.assertParseOK(["-a", "34"], 686 {'a': "34", 'boo': None, 'foo': None}, 687 []) 688 689 def test_option_argument_joined_integer(self): 690 self.assertParseOK(["-b34"], 691 {'a': None, 'boo': 34, 'foo': None}, 692 []) 693 694 def test_option_argument_split_negative_integer(self): 695 self.assertParseOK(["-b", "-5"], 696 {'a': None, 'boo': -5, 'foo': None}, 697 []) 698 699 def test_long_option_argument_joined(self): 700 self.assertParseOK(["--boo=13"], 701 {'a': None, 'boo': 13, 'foo': None}, 702 []) 703 704 def test_long_option_argument_split(self): 705 self.assertParseOK(["--boo", "111"], 706 {'a': None, 'boo': 111, 'foo': None}, 707 []) 708 709 def test_long_option_short_option(self): 710 self.assertParseOK(["--foo=bar", "-axyz"], 711 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 712 []) 713 714 def test_abbrev_long_option(self): 715 self.assertParseOK(["--f=bar", "-axyz"], 716 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 717 []) 718 719 def test_defaults(self): 720 (options, args) = self.parser.parse_args([]) 721 defaults = self.parser.get_default_values() 722 self.assertEqual(vars(defaults), vars(options)) 723 724 def test_ambiguous_option(self): 725 self.parser.add_option("--foz", action="store", 726 type="string", dest="foo") 727 self.assertParseFail(["--f=bar"], 728 "ambiguous option: --f (--foo, --foz?)") 729 730 731 def test_short_and_long_option_split(self): 732 self.assertParseOK(["-a", "xyz", "--foo", "bar"], 733 {'a': 'xyz', 'boo': None, 'foo': ["bar"]}, 734 []) 735 736 def test_short_option_split_long_option_append(self): 737 self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"], 738 {'a': None, 'boo': 123, 'foo': ["bar", "baz"]}, 739 []) 740 741 def test_short_option_split_one_positional_arg(self): 742 self.assertParseOK(["-a", "foo", "bar"], 743 {'a': "foo", 'boo': None, 'foo': None}, 744 ["bar"]) 745 746 def test_short_option_consumes_separator(self): 747 self.assertParseOK(["-a", "--", "foo", "bar"], 748 {'a': "--", 'boo': None, 'foo': None}, 749 ["foo", "bar"]) 750 self.assertParseOK(["-a", "--", "--foo", "bar"], 751 {'a': "--", 'boo': None, 'foo': ["bar"]}, 752 []) 753 754 def test_short_option_joined_and_separator(self): 755 self.assertParseOK(["-ab", "--", "--foo", "bar"], 756 {'a': "b", 'boo': None, 'foo': None}, 757 ["--foo", "bar"]), 758 759 def test_hyphen_becomes_positional_arg(self): 760 self.assertParseOK(["-ab", "-", "--foo", "bar"], 761 {'a': "b", 'boo': None, 'foo': ["bar"]}, 762 ["-"]) 763 764 def test_no_append_versus_append(self): 765 self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"], 766 {'a': None, 'boo': 5, 'foo': ["bar", "baz"]}, 767 []) 768 769 def test_option_consumes_optionlike_string(self): 770 self.assertParseOK(["-a", "-b3"], 771 {'a': "-b3", 'boo': None, 'foo': None}, 772 []) 773 774 def test_combined_single_invalid_option(self): 775 self.parser.add_option("-t", action="store_true") 776 self.assertParseFail(["-test"], 777 "no such option: -e") 778 779class TestBool(BaseTest): 780 def setUp(self): 781 options = [make_option("-v", 782 "--verbose", 783 action="store_true", 784 dest="verbose", 785 default=''), 786 make_option("-q", 787 "--quiet", 788 action="store_false", 789 dest="verbose")] 790 self.parser = OptionParser(option_list = options) 791 792 def test_bool_default(self): 793 self.assertParseOK([], 794 {'verbose': ''}, 795 []) 796 797 def test_bool_false(self): 798 (options, args) = self.assertParseOK(["-q"], 799 {'verbose': 0}, 800 []) 801 self.assertTrue(options.verbose is False) 802 803 def test_bool_true(self): 804 (options, args) = self.assertParseOK(["-v"], 805 {'verbose': 1}, 806 []) 807 self.assertTrue(options.verbose is True) 808 809 def test_bool_flicker_on_and_off(self): 810 self.assertParseOK(["-qvq", "-q", "-v"], 811 {'verbose': 1}, 812 []) 813 814class TestChoice(BaseTest): 815 def setUp(self): 816 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 817 self.parser.add_option("-c", action="store", type="choice", 818 dest="choice", choices=["one", "two", "three"]) 819 820 def test_valid_choice(self): 821 self.assertParseOK(["-c", "one", "xyz"], 822 {'choice': 'one'}, 823 ["xyz"]) 824 825 def test_invalid_choice(self): 826 self.assertParseFail(["-c", "four", "abc"], 827 "option -c: invalid choice: 'four' " 828 "(choose from 'one', 'two', 'three')") 829 830 def test_add_choice_option(self): 831 self.parser.add_option("-d", "--default", 832 choices=["four", "five", "six"]) 833 opt = self.parser.get_option("-d") 834 self.assertEqual(opt.type, "choice") 835 self.assertEqual(opt.action, "store") 836 837class TestCount(BaseTest): 838 def setUp(self): 839 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 840 self.v_opt = make_option("-v", action="count", dest="verbose") 841 self.parser.add_option(self.v_opt) 842 self.parser.add_option("--verbose", type="int", dest="verbose") 843 self.parser.add_option("-q", "--quiet", 844 action="store_const", dest="verbose", const=0) 845 846 def test_empty(self): 847 self.assertParseOK([], {'verbose': None}, []) 848 849 def test_count_one(self): 850 self.assertParseOK(["-v"], {'verbose': 1}, []) 851 852 def test_count_three(self): 853 self.assertParseOK(["-vvv"], {'verbose': 3}, []) 854 855 def test_count_three_apart(self): 856 self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, []) 857 858 def test_count_override_amount(self): 859 self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, []) 860 861 def test_count_override_quiet(self): 862 self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, []) 863 864 def test_count_overriding(self): 865 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], 866 {'verbose': 1}, []) 867 868 def test_count_interspersed_args(self): 869 self.assertParseOK(["--quiet", "3", "-v"], 870 {'verbose': 1}, 871 ["3"]) 872 873 def test_count_no_interspersed_args(self): 874 self.parser.disable_interspersed_args() 875 self.assertParseOK(["--quiet", "3", "-v"], 876 {'verbose': 0}, 877 ["3", "-v"]) 878 879 def test_count_no_such_option(self): 880 self.assertParseFail(["-q3", "-v"], "no such option: -3") 881 882 def test_count_option_no_value(self): 883 self.assertParseFail(["--quiet=3", "-v"], 884 "--quiet option does not take a value") 885 886 def test_count_with_default(self): 887 self.parser.set_default('verbose', 0) 888 self.assertParseOK([], {'verbose':0}, []) 889 890 def test_count_overriding_default(self): 891 self.parser.set_default('verbose', 0) 892 self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], 893 {'verbose': 1}, []) 894 895class TestMultipleArgs(BaseTest): 896 def setUp(self): 897 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 898 self.parser.add_option("-p", "--point", 899 action="store", nargs=3, type="float", dest="point") 900 901 def test_nargs_with_positional_args(self): 902 self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"], 903 {'point': (1.0, 2.5, -4.3)}, 904 ["foo", "xyz"]) 905 906 def test_nargs_long_opt(self): 907 self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"], 908 {'point': (-1.0, 2.5, -0.0)}, 909 ["xyz"]) 910 911 def test_nargs_invalid_float_value(self): 912 self.assertParseFail(["-p", "1.0", "2x", "3.5"], 913 "option -p: " 914 "invalid floating-point value: '2x'") 915 916 def test_nargs_required_values(self): 917 self.assertParseFail(["--point", "1.0", "3.5"], 918 "--point option requires 3 arguments") 919 920class TestMultipleArgsAppend(BaseTest): 921 def setUp(self): 922 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 923 self.parser.add_option("-p", "--point", action="store", nargs=3, 924 type="float", dest="point") 925 self.parser.add_option("-f", "--foo", action="append", nargs=2, 926 type="int", dest="foo") 927 self.parser.add_option("-z", "--zero", action="append_const", 928 dest="foo", const=(0, 0)) 929 930 def test_nargs_append(self): 931 self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"], 932 {'point': None, 'foo': [(4, -3), (1, 666)]}, 933 ["blah"]) 934 935 def test_nargs_append_required_values(self): 936 self.assertParseFail(["-f4,3"], 937 "-f option requires 2 arguments") 938 939 def test_nargs_append_simple(self): 940 self.assertParseOK(["--foo=3", "4"], 941 {'point': None, 'foo':[(3, 4)]}, 942 []) 943 944 def test_nargs_append_const(self): 945 self.assertParseOK(["--zero", "--foo", "3", "4", "-z"], 946 {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]}, 947 []) 948 949class TestVersion(BaseTest): 950 def test_version(self): 951 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 952 version="%prog 0.1") 953 save_argv = sys.argv[:] 954 try: 955 sys.argv[0] = os.path.join(os.curdir, "foo", "bar") 956 self.assertOutput(["--version"], "bar 0.1\n") 957 finally: 958 sys.argv[:] = save_argv 959 960 def test_no_version(self): 961 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 962 self.assertParseFail(["--version"], 963 "no such option: --version") 964 965# -- Test conflicting default values and parser.parse_args() ----------- 966 967class TestConflictingDefaults(BaseTest): 968 """Conflicting default values: the last one should win.""" 969 def setUp(self): 970 self.parser = OptionParser(option_list=[ 971 make_option("-v", action="store_true", dest="verbose", default=1)]) 972 973 def test_conflict_default(self): 974 self.parser.add_option("-q", action="store_false", dest="verbose", 975 default=0) 976 self.assertParseOK([], {'verbose': 0}, []) 977 978 def test_conflict_default_none(self): 979 self.parser.add_option("-q", action="store_false", dest="verbose", 980 default=None) 981 self.assertParseOK([], {'verbose': None}, []) 982 983class TestOptionGroup(BaseTest): 984 def setUp(self): 985 self.parser = OptionParser(usage=SUPPRESS_USAGE) 986 987 def test_option_group_create_instance(self): 988 group = OptionGroup(self.parser, "Spam") 989 self.parser.add_option_group(group) 990 group.add_option("--spam", action="store_true", 991 help="spam spam spam spam") 992 self.assertParseOK(["--spam"], {'spam': 1}, []) 993 994 def test_add_group_no_group(self): 995 self.assertTypeError(self.parser.add_option_group, 996 "not an OptionGroup instance: None", None) 997 998 def test_add_group_invalid_arguments(self): 999 self.assertTypeError(self.parser.add_option_group, 1000 "invalid arguments", None, None) 1001 1002 def test_add_group_wrong_parser(self): 1003 group = OptionGroup(self.parser, "Spam") 1004 group.parser = OptionParser() 1005 self.assertRaises(self.parser.add_option_group, (group,), None, 1006 ValueError, "invalid OptionGroup (wrong parser)") 1007 1008 def test_group_manipulate(self): 1009 group = self.parser.add_option_group("Group 2", 1010 description="Some more options") 1011 group.set_title("Bacon") 1012 group.add_option("--bacon", type="int") 1013 self.assertTrue(self.parser.get_option_group("--bacon"), group) 1014 1015# -- Test extending and parser.parse_args() ---------------------------- 1016 1017class TestExtendAddTypes(BaseTest): 1018 def setUp(self): 1019 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1020 option_class=self.MyOption) 1021 self.parser.add_option("-a", None, type="string", dest="a") 1022 self.parser.add_option("-f", "--file", type="file", dest="file") 1023 1024 def tearDown(self): 1025 if os.path.isdir(os_helper.TESTFN): 1026 os.rmdir(os_helper.TESTFN) 1027 elif os.path.isfile(os_helper.TESTFN): 1028 os.unlink(os_helper.TESTFN) 1029 1030 class MyOption (Option): 1031 def check_file(option, opt, value): 1032 if not os.path.exists(value): 1033 raise OptionValueError("%s: file does not exist" % value) 1034 elif not os.path.isfile(value): 1035 raise OptionValueError("%s: not a regular file" % value) 1036 return value 1037 1038 TYPES = Option.TYPES + ("file",) 1039 TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER) 1040 TYPE_CHECKER["file"] = check_file 1041 1042 def test_filetype_ok(self): 1043 os_helper.create_empty_file(os_helper.TESTFN) 1044 self.assertParseOK(["--file", os_helper.TESTFN, "-afoo"], 1045 {'file': os_helper.TESTFN, 'a': 'foo'}, 1046 []) 1047 1048 def test_filetype_noexist(self): 1049 self.assertParseFail(["--file", os_helper.TESTFN, "-afoo"], 1050 "%s: file does not exist" % 1051 os_helper.TESTFN) 1052 1053 def test_filetype_notfile(self): 1054 os.mkdir(os_helper.TESTFN) 1055 self.assertParseFail(["--file", os_helper.TESTFN, "-afoo"], 1056 "%s: not a regular file" % 1057 os_helper.TESTFN) 1058 1059 1060class TestExtendAddActions(BaseTest): 1061 def setUp(self): 1062 options = [self.MyOption("-a", "--apple", action="extend", 1063 type="string", dest="apple")] 1064 self.parser = OptionParser(option_list=options) 1065 1066 class MyOption (Option): 1067 ACTIONS = Option.ACTIONS + ("extend",) 1068 STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) 1069 TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) 1070 1071 def take_action(self, action, dest, opt, value, values, parser): 1072 if action == "extend": 1073 lvalue = value.split(",") 1074 values.ensure_value(dest, []).extend(lvalue) 1075 else: 1076 Option.take_action(self, action, dest, opt, parser, value, 1077 values) 1078 1079 def test_extend_add_action(self): 1080 self.assertParseOK(["-afoo,bar", "--apple=blah"], 1081 {'apple': ["foo", "bar", "blah"]}, 1082 []) 1083 1084 def test_extend_add_action_normal(self): 1085 self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"], 1086 {'apple': ["foo", "bar", "x", "y"]}, 1087 []) 1088 1089# -- Test callbacks and parser.parse_args() ---------------------------- 1090 1091class TestCallback(BaseTest): 1092 def setUp(self): 1093 options = [make_option("-x", 1094 None, 1095 action="callback", 1096 callback=self.process_opt), 1097 make_option("-f", 1098 "--file", 1099 action="callback", 1100 callback=self.process_opt, 1101 type="string", 1102 dest="filename")] 1103 self.parser = OptionParser(option_list=options) 1104 1105 def process_opt(self, option, opt, value, parser_): 1106 if opt == "-x": 1107 self.assertEqual(option._short_opts, ["-x"]) 1108 self.assertEqual(option._long_opts, []) 1109 self.assertTrue(parser_ is self.parser) 1110 self.assertTrue(value is None) 1111 self.assertEqual(vars(parser_.values), {'filename': None}) 1112 1113 parser_.values.x = 42 1114 elif opt == "--file": 1115 self.assertEqual(option._short_opts, ["-f"]) 1116 self.assertEqual(option._long_opts, ["--file"]) 1117 self.assertTrue(parser_ is self.parser) 1118 self.assertEqual(value, "foo") 1119 self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42}) 1120 1121 setattr(parser_.values, option.dest, value) 1122 else: 1123 self.fail("Unknown option %r in process_opt." % opt) 1124 1125 def test_callback(self): 1126 self.assertParseOK(["-x", "--file=foo"], 1127 {'filename': "foo", 'x': 42}, 1128 []) 1129 1130 def test_callback_help(self): 1131 # This test was prompted by SF bug #960515 -- the point is 1132 # not to inspect the help text, just to make sure that 1133 # format_help() doesn't crash. 1134 parser = OptionParser(usage=SUPPRESS_USAGE) 1135 parser.remove_option("-h") 1136 parser.add_option("-t", "--test", action="callback", 1137 callback=lambda: None, type="string", 1138 help="foo") 1139 1140 expected_help = ("Options:\n" 1141 " -t TEST, --test=TEST foo\n") 1142 self.assertHelp(parser, expected_help) 1143 1144 1145class TestCallbackExtraArgs(BaseTest): 1146 def setUp(self): 1147 options = [make_option("-p", "--point", action="callback", 1148 callback=self.process_tuple, 1149 callback_args=(3, int), type="string", 1150 dest="points", default=[])] 1151 self.parser = OptionParser(option_list=options) 1152 1153 def process_tuple(self, option, opt, value, parser_, len, type): 1154 self.assertEqual(len, 3) 1155 self.assertTrue(type is int) 1156 1157 if opt == "-p": 1158 self.assertEqual(value, "1,2,3") 1159 elif opt == "--point": 1160 self.assertEqual(value, "4,5,6") 1161 1162 value = tuple(map(type, value.split(","))) 1163 getattr(parser_.values, option.dest).append(value) 1164 1165 def test_callback_extra_args(self): 1166 self.assertParseOK(["-p1,2,3", "--point", "4,5,6"], 1167 {'points': [(1,2,3), (4,5,6)]}, 1168 []) 1169 1170class TestCallbackMeddleArgs(BaseTest): 1171 def setUp(self): 1172 options = [make_option(str(x), action="callback", 1173 callback=self.process_n, dest='things') 1174 for x in range(-1, -6, -1)] 1175 self.parser = OptionParser(option_list=options) 1176 1177 # Callback that meddles in rargs, largs 1178 def process_n(self, option, opt, value, parser_): 1179 # option is -3, -5, etc. 1180 nargs = int(opt[1:]) 1181 rargs = parser_.rargs 1182 if len(rargs) < nargs: 1183 self.fail("Expected %d arguments for %s option." % (nargs, opt)) 1184 dest = parser_.values.ensure_value(option.dest, []) 1185 dest.append(tuple(rargs[0:nargs])) 1186 parser_.largs.append(nargs) 1187 del rargs[0:nargs] 1188 1189 def test_callback_meddle_args(self): 1190 self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"], 1191 {'things': [("foo",), ("bar", "baz", "qux")]}, 1192 [1, 3]) 1193 1194 def test_callback_meddle_args_separator(self): 1195 self.assertParseOK(["-2", "foo", "--"], 1196 {'things': [('foo', '--')]}, 1197 [2]) 1198 1199class TestCallbackManyArgs(BaseTest): 1200 def setUp(self): 1201 options = [make_option("-a", "--apple", action="callback", nargs=2, 1202 callback=self.process_many, type="string"), 1203 make_option("-b", "--bob", action="callback", nargs=3, 1204 callback=self.process_many, type="int")] 1205 self.parser = OptionParser(option_list=options) 1206 1207 def process_many(self, option, opt, value, parser_): 1208 if opt == "-a": 1209 self.assertEqual(value, ("foo", "bar")) 1210 elif opt == "--apple": 1211 self.assertEqual(value, ("ding", "dong")) 1212 elif opt == "-b": 1213 self.assertEqual(value, (1, 2, 3)) 1214 elif opt == "--bob": 1215 self.assertEqual(value, (-666, 42, 0)) 1216 1217 def test_many_args(self): 1218 self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong", 1219 "-b", "1", "2", "3", "--bob", "-666", "42", 1220 "0"], 1221 {"apple": None, "bob": None}, 1222 []) 1223 1224class TestCallbackCheckAbbrev(BaseTest): 1225 def setUp(self): 1226 self.parser = OptionParser() 1227 self.parser.add_option("--foo-bar", action="callback", 1228 callback=self.check_abbrev) 1229 1230 def check_abbrev(self, option, opt, value, parser): 1231 self.assertEqual(opt, "--foo-bar") 1232 1233 def test_abbrev_callback_expansion(self): 1234 self.assertParseOK(["--foo"], {}, []) 1235 1236class TestCallbackVarArgs(BaseTest): 1237 def setUp(self): 1238 options = [make_option("-a", type="int", nargs=2, dest="a"), 1239 make_option("-b", action="store_true", dest="b"), 1240 make_option("-c", "--callback", action="callback", 1241 callback=self.variable_args, dest="c")] 1242 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1243 option_list=options) 1244 1245 def variable_args(self, option, opt, value, parser): 1246 self.assertTrue(value is None) 1247 value = [] 1248 rargs = parser.rargs 1249 while rargs: 1250 arg = rargs[0] 1251 if ((arg[:2] == "--" and len(arg) > 2) or 1252 (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): 1253 break 1254 else: 1255 value.append(arg) 1256 del rargs[0] 1257 setattr(parser.values, option.dest, value) 1258 1259 def test_variable_args(self): 1260 self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"], 1261 {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]}, 1262 []) 1263 1264 def test_consume_separator_stop_at_option(self): 1265 self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"], 1266 {'a': None, 1267 'b': True, 1268 'c': ["37", "--", "xxx"]}, 1269 ["hello"]) 1270 1271 def test_positional_arg_and_variable_args(self): 1272 self.assertParseOK(["hello", "-c", "foo", "-", "bar"], 1273 {'a': None, 1274 'b': None, 1275 'c':["foo", "-", "bar"]}, 1276 ["hello"]) 1277 1278 def test_stop_at_option(self): 1279 self.assertParseOK(["-c", "foo", "-b"], 1280 {'a': None, 'b': True, 'c': ["foo"]}, 1281 []) 1282 1283 def test_stop_at_invalid_option(self): 1284 self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5") 1285 1286 1287# -- Test conflict handling and parser.parse_args() -------------------- 1288 1289class ConflictBase(BaseTest): 1290 def setUp(self): 1291 options = [make_option("-v", "--verbose", action="count", 1292 dest="verbose", help="increment verbosity")] 1293 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1294 option_list=options) 1295 1296 def show_version(self, option, opt, value, parser): 1297 parser.values.show_version = 1 1298 1299class TestConflict(ConflictBase): 1300 """Use the default conflict resolution for Optik 1.2: error.""" 1301 def assertTrueconflict_error(self, func): 1302 err = self.assertRaises( 1303 func, ("-v", "--version"), {'action' : "callback", 1304 'callback' : self.show_version, 1305 'help' : "show version"}, 1306 OptionConflictError, 1307 "option -v/--version: conflicting option string(s): -v") 1308 1309 self.assertEqual(err.msg, "conflicting option string(s): -v") 1310 self.assertEqual(err.option_id, "-v/--version") 1311 1312 def test_conflict_error(self): 1313 self.assertTrueconflict_error(self.parser.add_option) 1314 1315 def test_conflict_error_group(self): 1316 group = OptionGroup(self.parser, "Group 1") 1317 self.assertTrueconflict_error(group.add_option) 1318 1319 def test_no_such_conflict_handler(self): 1320 self.assertRaises( 1321 self.parser.set_conflict_handler, ('foo',), None, 1322 ValueError, "invalid conflict_resolution value 'foo'") 1323 1324 1325class TestConflictResolve(ConflictBase): 1326 def setUp(self): 1327 ConflictBase.setUp(self) 1328 self.parser.set_conflict_handler("resolve") 1329 self.parser.add_option("-v", "--version", action="callback", 1330 callback=self.show_version, help="show version") 1331 1332 def test_conflict_resolve(self): 1333 v_opt = self.parser.get_option("-v") 1334 verbose_opt = self.parser.get_option("--verbose") 1335 version_opt = self.parser.get_option("--version") 1336 1337 self.assertTrue(v_opt is version_opt) 1338 self.assertTrue(v_opt is not verbose_opt) 1339 self.assertEqual(v_opt._long_opts, ["--version"]) 1340 self.assertEqual(version_opt._short_opts, ["-v"]) 1341 self.assertEqual(version_opt._long_opts, ["--version"]) 1342 self.assertEqual(verbose_opt._short_opts, []) 1343 self.assertEqual(verbose_opt._long_opts, ["--verbose"]) 1344 1345 def test_conflict_resolve_help(self): 1346 self.assertOutput(["-h"], """\ 1347Options: 1348 --verbose increment verbosity 1349 -h, --help show this help message and exit 1350 -v, --version show version 1351""") 1352 1353 def test_conflict_resolve_short_opt(self): 1354 self.assertParseOK(["-v"], 1355 {'verbose': None, 'show_version': 1}, 1356 []) 1357 1358 def test_conflict_resolve_long_opt(self): 1359 self.assertParseOK(["--verbose"], 1360 {'verbose': 1}, 1361 []) 1362 1363 def test_conflict_resolve_long_opts(self): 1364 self.assertParseOK(["--verbose", "--version"], 1365 {'verbose': 1, 'show_version': 1}, 1366 []) 1367 1368class TestConflictOverride(BaseTest): 1369 def setUp(self): 1370 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 1371 self.parser.set_conflict_handler("resolve") 1372 self.parser.add_option("-n", "--dry-run", 1373 action="store_true", dest="dry_run", 1374 help="don't do anything") 1375 self.parser.add_option("--dry-run", "-n", 1376 action="store_const", const=42, dest="dry_run", 1377 help="dry run mode") 1378 1379 def test_conflict_override_opts(self): 1380 opt = self.parser.get_option("--dry-run") 1381 self.assertEqual(opt._short_opts, ["-n"]) 1382 self.assertEqual(opt._long_opts, ["--dry-run"]) 1383 1384 def test_conflict_override_help(self): 1385 self.assertOutput(["-h"], """\ 1386Options: 1387 -h, --help show this help message and exit 1388 -n, --dry-run dry run mode 1389""") 1390 1391 def test_conflict_override_args(self): 1392 self.assertParseOK(["-n"], 1393 {'dry_run': 42}, 1394 []) 1395 1396# -- Other testing. ---------------------------------------------------- 1397 1398_expected_help_basic = """\ 1399Usage: bar.py [options] 1400 1401Options: 1402 -a APPLE throw APPLEs at basket 1403 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the 1404 evil spirits that cause trouble and mayhem) 1405 --foo=FOO store FOO in the foo list for later fooing 1406 -h, --help show this help message and exit 1407""" 1408 1409_expected_help_long_opts_first = """\ 1410Usage: bar.py [options] 1411 1412Options: 1413 -a APPLE throw APPLEs at basket 1414 --boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the 1415 evil spirits that cause trouble and mayhem) 1416 --foo=FOO store FOO in the foo list for later fooing 1417 --help, -h show this help message and exit 1418""" 1419 1420_expected_help_title_formatter = """\ 1421Usage 1422===== 1423 bar.py [options] 1424 1425Options 1426======= 1427-a APPLE throw APPLEs at basket 1428--boo=NUM, -b NUM shout "boo!" NUM times (in order to frighten away all the 1429 evil spirits that cause trouble and mayhem) 1430--foo=FOO store FOO in the foo list for later fooing 1431--help, -h show this help message and exit 1432""" 1433 1434_expected_help_short_lines = """\ 1435Usage: bar.py [options] 1436 1437Options: 1438 -a APPLE throw APPLEs at basket 1439 -b NUM, --boo=NUM shout "boo!" NUM times (in order to 1440 frighten away all the evil spirits 1441 that cause trouble and mayhem) 1442 --foo=FOO store FOO in the foo list for later 1443 fooing 1444 -h, --help show this help message and exit 1445""" 1446 1447_expected_very_help_short_lines = """\ 1448Usage: bar.py [options] 1449 1450Options: 1451 -a APPLE 1452 throw 1453 APPLEs at 1454 basket 1455 -b NUM, --boo=NUM 1456 shout 1457 "boo!" NUM 1458 times (in 1459 order to 1460 frighten 1461 away all 1462 the evil 1463 spirits 1464 that cause 1465 trouble and 1466 mayhem) 1467 --foo=FOO 1468 store FOO 1469 in the foo 1470 list for 1471 later 1472 fooing 1473 -h, --help 1474 show this 1475 help 1476 message and 1477 exit 1478""" 1479 1480class TestHelp(BaseTest): 1481 def setUp(self): 1482 self.parser = self.make_parser(80) 1483 1484 def make_parser(self, columns): 1485 options = [ 1486 make_option("-a", type="string", dest='a', 1487 metavar="APPLE", help="throw APPLEs at basket"), 1488 make_option("-b", "--boo", type="int", dest='boo', 1489 metavar="NUM", 1490 help= 1491 "shout \"boo!\" NUM times (in order to frighten away " 1492 "all the evil spirits that cause trouble and mayhem)"), 1493 make_option("--foo", action="append", type="string", dest='foo', 1494 help="store FOO in the foo list for later fooing"), 1495 ] 1496 1497 # We need to set COLUMNS for the OptionParser constructor, but 1498 # we must restore its original value -- otherwise, this test 1499 # screws things up for other tests when it's part of the Python 1500 # test suite. 1501 with os_helper.EnvironmentVarGuard() as env: 1502 env['COLUMNS'] = str(columns) 1503 return InterceptingOptionParser(option_list=options) 1504 1505 def assertHelpEquals(self, expected_output): 1506 save_argv = sys.argv[:] 1507 try: 1508 # Make optparse believe bar.py is being executed. 1509 sys.argv[0] = os.path.join("foo", "bar.py") 1510 self.assertOutput(["-h"], expected_output) 1511 finally: 1512 sys.argv[:] = save_argv 1513 1514 def test_help(self): 1515 self.assertHelpEquals(_expected_help_basic) 1516 1517 def test_help_old_usage(self): 1518 self.parser.set_usage("Usage: %prog [options]") 1519 self.assertHelpEquals(_expected_help_basic) 1520 1521 def test_help_long_opts_first(self): 1522 self.parser.formatter.short_first = 0 1523 self.assertHelpEquals(_expected_help_long_opts_first) 1524 1525 def test_help_title_formatter(self): 1526 with os_helper.EnvironmentVarGuard() as env: 1527 env["COLUMNS"] = "80" 1528 self.parser.formatter = TitledHelpFormatter() 1529 self.assertHelpEquals(_expected_help_title_formatter) 1530 1531 def test_wrap_columns(self): 1532 # Ensure that wrapping respects $COLUMNS environment variable. 1533 # Need to reconstruct the parser, since that's the only time 1534 # we look at $COLUMNS. 1535 self.parser = self.make_parser(60) 1536 self.assertHelpEquals(_expected_help_short_lines) 1537 self.parser = self.make_parser(0) 1538 self.assertHelpEquals(_expected_very_help_short_lines) 1539 1540 def test_help_unicode(self): 1541 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) 1542 self.parser.add_option("-a", action="store_true", help="ol\u00E9!") 1543 expect = """\ 1544Options: 1545 -h, --help show this help message and exit 1546 -a ol\u00E9! 1547""" 1548 self.assertHelpEquals(expect) 1549 1550 def test_help_unicode_description(self): 1551 self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, 1552 description="ol\u00E9!") 1553 expect = """\ 1554ol\u00E9! 1555 1556Options: 1557 -h, --help show this help message and exit 1558""" 1559 self.assertHelpEquals(expect) 1560 1561 def test_help_description_groups(self): 1562 self.parser.set_description( 1563 "This is the program description for %prog. %prog has " 1564 "an option group as well as single options.") 1565 1566 group = OptionGroup( 1567 self.parser, "Dangerous Options", 1568 "Caution: use of these options is at your own risk. " 1569 "It is believed that some of them bite.") 1570 group.add_option("-g", action="store_true", help="Group option.") 1571 self.parser.add_option_group(group) 1572 1573 expect = """\ 1574Usage: bar.py [options] 1575 1576This is the program description for bar.py. bar.py has an option group as 1577well as single options. 1578 1579Options: 1580 -a APPLE throw APPLEs at basket 1581 -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the 1582 evil spirits that cause trouble and mayhem) 1583 --foo=FOO store FOO in the foo list for later fooing 1584 -h, --help show this help message and exit 1585 1586 Dangerous Options: 1587 Caution: use of these options is at your own risk. It is believed 1588 that some of them bite. 1589 1590 -g Group option. 1591""" 1592 1593 self.assertHelpEquals(expect) 1594 1595 self.parser.epilog = "Please report bugs to /dev/null." 1596 self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n") 1597 1598 1599class TestMatchAbbrev(BaseTest): 1600 def test_match_abbrev(self): 1601 self.assertEqual(_match_abbrev("--f", 1602 {"--foz": None, 1603 "--foo": None, 1604 "--fie": None, 1605 "--f": None}), 1606 "--f") 1607 1608 def test_match_abbrev_error(self): 1609 s = "--f" 1610 wordmap = {"--foz": None, "--foo": None, "--fie": None} 1611 self.assertRaises( 1612 _match_abbrev, (s, wordmap), None, 1613 BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)") 1614 1615 1616class TestParseNumber(BaseTest): 1617 def setUp(self): 1618 self.parser = InterceptingOptionParser() 1619 self.parser.add_option("-n", type=int) 1620 self.parser.add_option("-l", type=int) 1621 1622 def test_parse_num_fail(self): 1623 self.assertRaises( 1624 _parse_num, ("", int), {}, 1625 ValueError, 1626 re.compile(r"invalid literal for int().*: '?'?")) 1627 self.assertRaises( 1628 _parse_num, ("0xOoops", int), {}, 1629 ValueError, 1630 re.compile(r"invalid literal for int().*: s?'?0xOoops'?")) 1631 1632 def test_parse_num_ok(self): 1633 self.assertEqual(_parse_num("0", int), 0) 1634 self.assertEqual(_parse_num("0x10", int), 16) 1635 self.assertEqual(_parse_num("0XA", int), 10) 1636 self.assertEqual(_parse_num("010", int), 8) 1637 self.assertEqual(_parse_num("0b11", int), 3) 1638 self.assertEqual(_parse_num("0b", int), 0) 1639 1640 def test_numeric_options(self): 1641 self.assertParseOK(["-n", "42", "-l", "0x20"], 1642 { "n": 42, "l": 0x20 }, []) 1643 self.assertParseOK(["-n", "0b0101", "-l010"], 1644 { "n": 5, "l": 8 }, []) 1645 self.assertParseFail(["-n008"], 1646 "option -n: invalid integer value: '008'") 1647 self.assertParseFail(["-l0b0123"], 1648 "option -l: invalid integer value: '0b0123'") 1649 self.assertParseFail(["-l", "0x12x"], 1650 "option -l: invalid integer value: '0x12x'") 1651 1652 1653class MiscTestCase(unittest.TestCase): 1654 def test__all__(self): 1655 not_exported = {'check_builtin', 'AmbiguousOptionError', 'NO_DEFAULT'} 1656 support.check__all__(self, optparse, not_exported=not_exported) 1657 1658 1659if __name__ == '__main__': 1660 unittest.main() 1661