PageRenderTime 63ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib-python/2.7/test/test_optparse.py

https://bitbucket.org/evelyn559/pypy
Python | 1619 lines | 1531 code | 67 blank | 21 comment | 22 complexity | c89e924aaca3eb1fb75a64ba44c57aff MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  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. import sys
  9. import os
  10. import re
  11. import copy
  12. import types
  13. import unittest
  14. from StringIO import StringIO
  15. from test import test_support
  16. from optparse import make_option, Option, \
  17. TitledHelpFormatter, OptionParser, OptionGroup, \
  18. SUPPRESS_USAGE, OptionError, OptionConflictError, \
  19. BadOptionError, OptionValueError, Values
  20. from optparse import _match_abbrev
  21. from optparse import _parse_num
  22. retype = type(re.compile(''))
  23. class InterceptedError(Exception):
  24. def __init__(self,
  25. error_message=None,
  26. exit_status=None,
  27. exit_message=None):
  28. self.error_message = error_message
  29. self.exit_status = exit_status
  30. self.exit_message = exit_message
  31. def __str__(self):
  32. return self.error_message or self.exit_message or "intercepted error"
  33. class InterceptingOptionParser(OptionParser):
  34. def exit(self, status=0, msg=None):
  35. raise InterceptedError(exit_status=status, exit_message=msg)
  36. def error(self, msg):
  37. raise InterceptedError(error_message=msg)
  38. class BaseTest(unittest.TestCase):
  39. def assertParseOK(self, args, expected_opts, expected_positional_args):
  40. """Assert the options are what we expected when parsing arguments.
  41. Otherwise, fail with a nicely formatted message.
  42. Keyword arguments:
  43. args -- A list of arguments to parse with OptionParser.
  44. expected_opts -- The options expected.
  45. expected_positional_args -- The positional arguments expected.
  46. Returns the options and positional args for further testing.
  47. """
  48. (options, positional_args) = self.parser.parse_args(args)
  49. optdict = vars(options)
  50. self.assertEqual(optdict, expected_opts,
  51. """
  52. Options are %(optdict)s.
  53. Should be %(expected_opts)s.
  54. Args were %(args)s.""" % locals())
  55. self.assertEqual(positional_args, expected_positional_args,
  56. """
  57. Positional arguments are %(positional_args)s.
  58. Should be %(expected_positional_args)s.
  59. Args were %(args)s.""" % locals ())
  60. return (options, positional_args)
  61. def assertRaises(self,
  62. func,
  63. args,
  64. kwargs,
  65. expected_exception,
  66. expected_message):
  67. """
  68. Assert that the expected exception is raised when calling a
  69. function, and that the right error message is included with
  70. that exception.
  71. Arguments:
  72. func -- the function to call
  73. args -- positional arguments to `func`
  74. kwargs -- keyword arguments to `func`
  75. expected_exception -- exception that should be raised
  76. expected_message -- expected exception message (or pattern
  77. if a compiled regex object)
  78. Returns the exception raised for further testing.
  79. """
  80. if args is None:
  81. args = ()
  82. if kwargs is None:
  83. kwargs = {}
  84. try:
  85. func(*args, **kwargs)
  86. except expected_exception, err:
  87. actual_message = str(err)
  88. if isinstance(expected_message, retype):
  89. self.assertTrue(expected_message.search(actual_message),
  90. """\
  91. expected exception message pattern:
  92. /%s/
  93. actual exception message:
  94. '''%s'''
  95. """ % (expected_message.pattern, actual_message))
  96. else:
  97. self.assertEqual(actual_message,
  98. expected_message,
  99. """\
  100. expected exception message:
  101. '''%s'''
  102. actual exception message:
  103. '''%s'''
  104. """ % (expected_message, actual_message))
  105. return err
  106. else:
  107. self.fail("""expected exception %(expected_exception)s not raised
  108. called %(func)r
  109. with args %(args)r
  110. and kwargs %(kwargs)r
  111. """ % locals ())
  112. # -- Assertions used in more than one class --------------------
  113. def assertParseFail(self, cmdline_args, expected_output):
  114. """
  115. Assert the parser fails with the expected message. Caller
  116. must ensure that self.parser is an InterceptingOptionParser.
  117. """
  118. try:
  119. self.parser.parse_args(cmdline_args)
  120. except InterceptedError, err:
  121. self.assertEqual(err.error_message, expected_output)
  122. else:
  123. self.assertFalse("expected parse failure")
  124. def assertOutput(self,
  125. cmdline_args,
  126. expected_output,
  127. expected_status=0,
  128. expected_error=None):
  129. """Assert the parser prints the expected output on stdout."""
  130. save_stdout = sys.stdout
  131. encoding = getattr(save_stdout, 'encoding', None)
  132. try:
  133. try:
  134. sys.stdout = StringIO()
  135. if encoding:
  136. sys.stdout.encoding = encoding
  137. self.parser.parse_args(cmdline_args)
  138. finally:
  139. output = sys.stdout.getvalue()
  140. sys.stdout = save_stdout
  141. except InterceptedError, err:
  142. self.assertTrue(
  143. type(output) is types.StringType,
  144. "expected output to be an ordinary string, not %r"
  145. % type(output))
  146. if output != expected_output:
  147. self.fail("expected: \n'''\n" + expected_output +
  148. "'''\nbut got \n'''\n" + output + "'''")
  149. self.assertEqual(err.exit_status, expected_status)
  150. self.assertEqual(err.exit_message, expected_error)
  151. else:
  152. self.assertFalse("expected parser.exit()")
  153. def assertTypeError(self, func, expected_message, *args):
  154. """Assert that TypeError is raised when executing func."""
  155. self.assertRaises(func, args, None, TypeError, expected_message)
  156. def assertHelp(self, parser, expected_help):
  157. actual_help = parser.format_help()
  158. if actual_help != expected_help:
  159. raise self.failureException(
  160. 'help text failure; expected:\n"' +
  161. expected_help + '"; got:\n"' +
  162. actual_help + '"\n')
  163. # -- Test make_option() aka Option -------------------------------------
  164. # It's not necessary to test correct options here. All the tests in the
  165. # parser.parse_args() section deal with those, because they're needed
  166. # there.
  167. class TestOptionChecks(BaseTest):
  168. def setUp(self):
  169. self.parser = OptionParser(usage=SUPPRESS_USAGE)
  170. def assertOptionError(self, expected_message, args=[], kwargs={}):
  171. self.assertRaises(make_option, args, kwargs,
  172. OptionError, expected_message)
  173. def test_opt_string_empty(self):
  174. self.assertTypeError(make_option,
  175. "at least one option string must be supplied")
  176. def test_opt_string_too_short(self):
  177. self.assertOptionError(
  178. "invalid option string 'b': must be at least two characters long",
  179. ["b"])
  180. def test_opt_string_short_invalid(self):
  181. self.assertOptionError(
  182. "invalid short option string '--': must be "
  183. "of the form -x, (x any non-dash char)",
  184. ["--"])
  185. def test_opt_string_long_invalid(self):
  186. self.assertOptionError(
  187. "invalid long option string '---': "
  188. "must start with --, followed by non-dash",
  189. ["---"])
  190. def test_attr_invalid(self):
  191. self.assertOptionError(
  192. "option -b: invalid keyword arguments: bar, foo",
  193. ["-b"], {'foo': None, 'bar': None})
  194. def test_action_invalid(self):
  195. self.assertOptionError(
  196. "option -b: invalid action: 'foo'",
  197. ["-b"], {'action': 'foo'})
  198. def test_type_invalid(self):
  199. self.assertOptionError(
  200. "option -b: invalid option type: 'foo'",
  201. ["-b"], {'type': 'foo'})
  202. self.assertOptionError(
  203. "option -b: invalid option type: 'tuple'",
  204. ["-b"], {'type': tuple})
  205. def test_no_type_for_action(self):
  206. self.assertOptionError(
  207. "option -b: must not supply a type for action 'count'",
  208. ["-b"], {'action': 'count', 'type': 'int'})
  209. def test_no_choices_list(self):
  210. self.assertOptionError(
  211. "option -b/--bad: must supply a list of "
  212. "choices for type 'choice'",
  213. ["-b", "--bad"], {'type': "choice"})
  214. def test_bad_choices_list(self):
  215. typename = type('').__name__
  216. self.assertOptionError(
  217. "option -b/--bad: choices must be a list of "
  218. "strings ('%s' supplied)" % typename,
  219. ["-b", "--bad"],
  220. {'type': "choice", 'choices':"bad choices"})
  221. def test_no_choices_for_type(self):
  222. self.assertOptionError(
  223. "option -b: must not supply choices for type 'int'",
  224. ["-b"], {'type': 'int', 'choices':"bad"})
  225. def test_no_const_for_action(self):
  226. self.assertOptionError(
  227. "option -b: 'const' must not be supplied for action 'store'",
  228. ["-b"], {'action': 'store', 'const': 1})
  229. def test_no_nargs_for_action(self):
  230. self.assertOptionError(
  231. "option -b: 'nargs' must not be supplied for action 'count'",
  232. ["-b"], {'action': 'count', 'nargs': 2})
  233. def test_callback_not_callable(self):
  234. self.assertOptionError(
  235. "option -b: callback not callable: 'foo'",
  236. ["-b"], {'action': 'callback',
  237. 'callback': 'foo'})
  238. def dummy(self):
  239. pass
  240. def test_callback_args_no_tuple(self):
  241. self.assertOptionError(
  242. "option -b: callback_args, if supplied, "
  243. "must be a tuple: not 'foo'",
  244. ["-b"], {'action': 'callback',
  245. 'callback': self.dummy,
  246. 'callback_args': 'foo'})
  247. def test_callback_kwargs_no_dict(self):
  248. self.assertOptionError(
  249. "option -b: callback_kwargs, if supplied, "
  250. "must be a dict: not 'foo'",
  251. ["-b"], {'action': 'callback',
  252. 'callback': self.dummy,
  253. 'callback_kwargs': 'foo'})
  254. def test_no_callback_for_action(self):
  255. self.assertOptionError(
  256. "option -b: callback supplied ('foo') for non-callback option",
  257. ["-b"], {'action': 'store',
  258. 'callback': 'foo'})
  259. def test_no_callback_args_for_action(self):
  260. self.assertOptionError(
  261. "option -b: callback_args supplied for non-callback option",
  262. ["-b"], {'action': 'store',
  263. 'callback_args': 'foo'})
  264. def test_no_callback_kwargs_for_action(self):
  265. self.assertOptionError(
  266. "option -b: callback_kwargs supplied for non-callback option",
  267. ["-b"], {'action': 'store',
  268. 'callback_kwargs': 'foo'})
  269. class TestOptionParser(BaseTest):
  270. def setUp(self):
  271. self.parser = OptionParser()
  272. self.parser.add_option("-v", "--verbose", "-n", "--noisy",
  273. action="store_true", dest="verbose")
  274. self.parser.add_option("-q", "--quiet", "--silent",
  275. action="store_false", dest="verbose")
  276. def test_add_option_no_Option(self):
  277. self.assertTypeError(self.parser.add_option,
  278. "not an Option instance: None", None)
  279. def test_add_option_invalid_arguments(self):
  280. self.assertTypeError(self.parser.add_option,
  281. "invalid arguments", None, None)
  282. def test_get_option(self):
  283. opt1 = self.parser.get_option("-v")
  284. self.assertIsInstance(opt1, Option)
  285. self.assertEqual(opt1._short_opts, ["-v", "-n"])
  286. self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])
  287. self.assertEqual(opt1.action, "store_true")
  288. self.assertEqual(opt1.dest, "verbose")
  289. def test_get_option_equals(self):
  290. opt1 = self.parser.get_option("-v")
  291. opt2 = self.parser.get_option("--verbose")
  292. opt3 = self.parser.get_option("-n")
  293. opt4 = self.parser.get_option("--noisy")
  294. self.assertTrue(opt1 is opt2 is opt3 is opt4)
  295. def test_has_option(self):
  296. self.assertTrue(self.parser.has_option("-v"))
  297. self.assertTrue(self.parser.has_option("--verbose"))
  298. def assertTrueremoved(self):
  299. self.assertTrue(self.parser.get_option("-v") is None)
  300. self.assertTrue(self.parser.get_option("--verbose") is None)
  301. self.assertTrue(self.parser.get_option("-n") is None)
  302. self.assertTrue(self.parser.get_option("--noisy") is None)
  303. self.assertFalse(self.parser.has_option("-v"))
  304. self.assertFalse(self.parser.has_option("--verbose"))
  305. self.assertFalse(self.parser.has_option("-n"))
  306. self.assertFalse(self.parser.has_option("--noisy"))
  307. self.assertTrue(self.parser.has_option("-q"))
  308. self.assertTrue(self.parser.has_option("--silent"))
  309. def test_remove_short_opt(self):
  310. self.parser.remove_option("-n")
  311. self.assertTrueremoved()
  312. def test_remove_long_opt(self):
  313. self.parser.remove_option("--verbose")
  314. self.assertTrueremoved()
  315. def test_remove_nonexistent(self):
  316. self.assertRaises(self.parser.remove_option, ('foo',), None,
  317. ValueError, "no such option 'foo'")
  318. def test_refleak(self):
  319. # If an OptionParser is carrying around a reference to a large
  320. # object, various cycles can prevent it from being GC'd in
  321. # a timely fashion. destroy() breaks the cycles to ensure stuff
  322. # can be cleaned up.
  323. big_thing = [42]
  324. refcount = sys.getrefcount(big_thing)
  325. parser = OptionParser()
  326. parser.add_option("-a", "--aaarggh")
  327. parser.big_thing = big_thing
  328. parser.destroy()
  329. #self.assertEqual(refcount, sys.getrefcount(big_thing))
  330. del parser
  331. self.assertEqual(refcount, sys.getrefcount(big_thing))
  332. class TestOptionValues(BaseTest):
  333. def setUp(self):
  334. pass
  335. def test_basics(self):
  336. values = Values()
  337. self.assertEqual(vars(values), {})
  338. self.assertEqual(values, {})
  339. self.assertNotEqual(values, {"foo": "bar"})
  340. self.assertNotEqual(values, "")
  341. dict = {"foo": "bar", "baz": 42}
  342. values = Values(defaults=dict)
  343. self.assertEqual(vars(values), dict)
  344. self.assertEqual(values, dict)
  345. self.assertNotEqual(values, {"foo": "bar"})
  346. self.assertNotEqual(values, {})
  347. self.assertNotEqual(values, "")
  348. self.assertNotEqual(values, [])
  349. class TestTypeAliases(BaseTest):
  350. def setUp(self):
  351. self.parser = OptionParser()
  352. def test_str_aliases_string(self):
  353. self.parser.add_option("-s", type="str")
  354. self.assertEqual(self.parser.get_option("-s").type, "string")
  355. def test_new_type_object(self):
  356. self.parser.add_option("-s", type=str)
  357. self.assertEqual(self.parser.get_option("-s").type, "string")
  358. self.parser.add_option("-x", type=int)
  359. self.assertEqual(self.parser.get_option("-x").type, "int")
  360. def test_old_type_object(self):
  361. self.parser.add_option("-s", type=types.StringType)
  362. self.assertEqual(self.parser.get_option("-s").type, "string")
  363. self.parser.add_option("-x", type=types.IntType)
  364. self.assertEqual(self.parser.get_option("-x").type, "int")
  365. # Custom type for testing processing of default values.
  366. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
  367. def _check_duration(option, opt, value):
  368. try:
  369. if value[-1].isdigit():
  370. return int(value)
  371. else:
  372. return int(value[:-1]) * _time_units[value[-1]]
  373. except (ValueError, IndexError):
  374. raise OptionValueError(
  375. 'option %s: invalid duration: %r' % (opt, value))
  376. class DurationOption(Option):
  377. TYPES = Option.TYPES + ('duration',)
  378. TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  379. TYPE_CHECKER['duration'] = _check_duration
  380. class TestDefaultValues(BaseTest):
  381. def setUp(self):
  382. self.parser = OptionParser()
  383. self.parser.add_option("-v", "--verbose", default=True)
  384. self.parser.add_option("-q", "--quiet", dest='verbose')
  385. self.parser.add_option("-n", type="int", default=37)
  386. self.parser.add_option("-m", type="int")
  387. self.parser.add_option("-s", default="foo")
  388. self.parser.add_option("-t")
  389. self.parser.add_option("-u", default=None)
  390. self.expected = { 'verbose': True,
  391. 'n': 37,
  392. 'm': None,
  393. 's': "foo",
  394. 't': None,
  395. 'u': None }
  396. def test_basic_defaults(self):
  397. self.assertEqual(self.parser.get_default_values(), self.expected)
  398. def test_mixed_defaults_post(self):
  399. self.parser.set_defaults(n=42, m=-100)
  400. self.expected.update({'n': 42, 'm': -100})
  401. self.assertEqual(self.parser.get_default_values(), self.expected)
  402. def test_mixed_defaults_pre(self):
  403. self.parser.set_defaults(x="barf", y="blah")
  404. self.parser.add_option("-x", default="frob")
  405. self.parser.add_option("-y")
  406. self.expected.update({'x': "frob", 'y': "blah"})
  407. self.assertEqual(self.parser.get_default_values(), self.expected)
  408. self.parser.remove_option("-y")
  409. self.parser.add_option("-y", default=None)
  410. self.expected.update({'y': None})
  411. self.assertEqual(self.parser.get_default_values(), self.expected)
  412. def test_process_default(self):
  413. self.parser.option_class = DurationOption
  414. self.parser.add_option("-d", type="duration", default=300)
  415. self.parser.add_option("-e", type="duration", default="6m")
  416. self.parser.set_defaults(n="42")
  417. self.expected.update({'d': 300, 'e': 360, 'n': 42})
  418. self.assertEqual(self.parser.get_default_values(), self.expected)
  419. self.parser.set_process_default_values(False)
  420. self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
  421. self.assertEqual(self.parser.get_default_values(), self.expected)
  422. class TestProgName(BaseTest):
  423. """
  424. Test that %prog expands to the right thing in usage, version,
  425. and help strings.
  426. """
  427. def assertUsage(self, parser, expected_usage):
  428. self.assertEqual(parser.get_usage(), expected_usage)
  429. def assertVersion(self, parser, expected_version):
  430. self.assertEqual(parser.get_version(), expected_version)
  431. def test_default_progname(self):
  432. # Make sure that program name taken from sys.argv[0] by default.
  433. save_argv = sys.argv[:]
  434. try:
  435. sys.argv[0] = os.path.join("foo", "bar", "baz.py")
  436. parser = OptionParser("%prog ...", version="%prog 1.2")
  437. expected_usage = "Usage: baz.py ...\n"
  438. self.assertUsage(parser, expected_usage)
  439. self.assertVersion(parser, "baz.py 1.2")
  440. self.assertHelp(parser,
  441. expected_usage + "\n" +
  442. "Options:\n"
  443. " --version show program's version number and exit\n"
  444. " -h, --help show this help message and exit\n")
  445. finally:
  446. sys.argv[:] = save_argv
  447. def test_custom_progname(self):
  448. parser = OptionParser(prog="thingy",
  449. version="%prog 0.1",
  450. usage="%prog arg arg")
  451. parser.remove_option("-h")
  452. parser.remove_option("--version")
  453. expected_usage = "Usage: thingy arg arg\n"
  454. self.assertUsage(parser, expected_usage)
  455. self.assertVersion(parser, "thingy 0.1")
  456. self.assertHelp(parser, expected_usage + "\n")
  457. class TestExpandDefaults(BaseTest):
  458. def setUp(self):
  459. self.parser = OptionParser(prog="test")
  460. self.help_prefix = """\
  461. Usage: test [options]
  462. Options:
  463. -h, --help show this help message and exit
  464. """
  465. self.file_help = "read from FILE [default: %default]"
  466. self.expected_help_file = self.help_prefix + \
  467. " -f FILE, --file=FILE read from FILE [default: foo.txt]\n"
  468. self.expected_help_none = self.help_prefix + \
  469. " -f FILE, --file=FILE read from FILE [default: none]\n"
  470. def test_option_default(self):
  471. self.parser.add_option("-f", "--file",
  472. default="foo.txt",
  473. help=self.file_help)
  474. self.assertHelp(self.parser, self.expected_help_file)
  475. def test_parser_default_1(self):
  476. self.parser.add_option("-f", "--file",
  477. help=self.file_help)
  478. self.parser.set_default('file', "foo.txt")
  479. self.assertHelp(self.parser, self.expected_help_file)
  480. def test_parser_default_2(self):
  481. self.parser.add_option("-f", "--file",
  482. help=self.file_help)
  483. self.parser.set_defaults(file="foo.txt")
  484. self.assertHelp(self.parser, self.expected_help_file)
  485. def test_no_default(self):
  486. self.parser.add_option("-f", "--file",
  487. help=self.file_help)
  488. self.assertHelp(self.parser, self.expected_help_none)
  489. def test_default_none_1(self):
  490. self.parser.add_option("-f", "--file",
  491. default=None,
  492. help=self.file_help)
  493. self.assertHelp(self.parser, self.expected_help_none)
  494. def test_default_none_2(self):
  495. self.parser.add_option("-f", "--file",
  496. help=self.file_help)
  497. self.parser.set_defaults(file=None)
  498. self.assertHelp(self.parser, self.expected_help_none)
  499. def test_float_default(self):
  500. self.parser.add_option(
  501. "-p", "--prob",
  502. help="blow up with probability PROB [default: %default]")
  503. self.parser.set_defaults(prob=0.43)
  504. expected_help = self.help_prefix + \
  505. " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n"
  506. self.assertHelp(self.parser, expected_help)
  507. def test_alt_expand(self):
  508. self.parser.add_option("-f", "--file",
  509. default="foo.txt",
  510. help="read from FILE [default: *DEFAULT*]")
  511. self.parser.formatter.default_tag = "*DEFAULT*"
  512. self.assertHelp(self.parser, self.expected_help_file)
  513. def test_no_expand(self):
  514. self.parser.add_option("-f", "--file",
  515. default="foo.txt",
  516. help="read from %default file")
  517. self.parser.formatter.default_tag = None
  518. expected_help = self.help_prefix + \
  519. " -f FILE, --file=FILE read from %default file\n"
  520. self.assertHelp(self.parser, expected_help)
  521. # -- Test parser.parse_args() ------------------------------------------
  522. class TestStandard(BaseTest):
  523. def setUp(self):
  524. options = [make_option("-a", type="string"),
  525. make_option("-b", "--boo", type="int", dest='boo'),
  526. make_option("--foo", action="append")]
  527. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  528. option_list=options)
  529. def test_required_value(self):
  530. self.assertParseFail(["-a"], "-a option requires an argument")
  531. def test_invalid_integer(self):
  532. self.assertParseFail(["-b", "5x"],
  533. "option -b: invalid integer value: '5x'")
  534. def test_no_such_option(self):
  535. self.assertParseFail(["--boo13"], "no such option: --boo13")
  536. def test_long_invalid_integer(self):
  537. self.assertParseFail(["--boo=x5"],
  538. "option --boo: invalid integer value: 'x5'")
  539. def test_empty(self):
  540. self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
  541. def test_shortopt_empty_longopt_append(self):
  542. self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
  543. {'a': "", 'boo': None, 'foo': ["blah", ""]},
  544. [])
  545. def test_long_option_append(self):
  546. self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
  547. {'a': None,
  548. 'boo': None,
  549. 'foo': ["bar", "", "x"]},
  550. [])
  551. def test_option_argument_joined(self):
  552. self.assertParseOK(["-abc"],
  553. {'a': "bc", 'boo': None, 'foo': None},
  554. [])
  555. def test_option_argument_split(self):
  556. self.assertParseOK(["-a", "34"],
  557. {'a': "34", 'boo': None, 'foo': None},
  558. [])
  559. def test_option_argument_joined_integer(self):
  560. self.assertParseOK(["-b34"],
  561. {'a': None, 'boo': 34, 'foo': None},
  562. [])
  563. def test_option_argument_split_negative_integer(self):
  564. self.assertParseOK(["-b", "-5"],
  565. {'a': None, 'boo': -5, 'foo': None},
  566. [])
  567. def test_long_option_argument_joined(self):
  568. self.assertParseOK(["--boo=13"],
  569. {'a': None, 'boo': 13, 'foo': None},
  570. [])
  571. def test_long_option_argument_split(self):
  572. self.assertParseOK(["--boo", "111"],
  573. {'a': None, 'boo': 111, 'foo': None},
  574. [])
  575. def test_long_option_short_option(self):
  576. self.assertParseOK(["--foo=bar", "-axyz"],
  577. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  578. [])
  579. def test_abbrev_long_option(self):
  580. self.assertParseOK(["--f=bar", "-axyz"],
  581. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  582. [])
  583. def test_defaults(self):
  584. (options, args) = self.parser.parse_args([])
  585. defaults = self.parser.get_default_values()
  586. self.assertEqual(vars(defaults), vars(options))
  587. def test_ambiguous_option(self):
  588. self.parser.add_option("--foz", action="store",
  589. type="string", dest="foo")
  590. self.assertParseFail(["--f=bar"],
  591. "ambiguous option: --f (--foo, --foz?)")
  592. def test_short_and_long_option_split(self):
  593. self.assertParseOK(["-a", "xyz", "--foo", "bar"],
  594. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  595. []),
  596. def test_short_option_split_long_option_append(self):
  597. self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
  598. {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
  599. [])
  600. def test_short_option_split_one_positional_arg(self):
  601. self.assertParseOK(["-a", "foo", "bar"],
  602. {'a': "foo", 'boo': None, 'foo': None},
  603. ["bar"]),
  604. def test_short_option_consumes_separator(self):
  605. self.assertParseOK(["-a", "--", "foo", "bar"],
  606. {'a': "--", 'boo': None, 'foo': None},
  607. ["foo", "bar"]),
  608. self.assertParseOK(["-a", "--", "--foo", "bar"],
  609. {'a': "--", 'boo': None, 'foo': ["bar"]},
  610. []),
  611. def test_short_option_joined_and_separator(self):
  612. self.assertParseOK(["-ab", "--", "--foo", "bar"],
  613. {'a': "b", 'boo': None, 'foo': None},
  614. ["--foo", "bar"]),
  615. def test_hyphen_becomes_positional_arg(self):
  616. self.assertParseOK(["-ab", "-", "--foo", "bar"],
  617. {'a': "b", 'boo': None, 'foo': ["bar"]},
  618. ["-"])
  619. def test_no_append_versus_append(self):
  620. self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
  621. {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
  622. [])
  623. def test_option_consumes_optionlike_string(self):
  624. self.assertParseOK(["-a", "-b3"],
  625. {'a': "-b3", 'boo': None, 'foo': None},
  626. [])
  627. def test_combined_single_invalid_option(self):
  628. self.parser.add_option("-t", action="store_true")
  629. self.assertParseFail(["-test"],
  630. "no such option: -e")
  631. class TestBool(BaseTest):
  632. def setUp(self):
  633. options = [make_option("-v",
  634. "--verbose",
  635. action="store_true",
  636. dest="verbose",
  637. default=''),
  638. make_option("-q",
  639. "--quiet",
  640. action="store_false",
  641. dest="verbose")]
  642. self.parser = OptionParser(option_list = options)
  643. def test_bool_default(self):
  644. self.assertParseOK([],
  645. {'verbose': ''},
  646. [])
  647. def test_bool_false(self):
  648. (options, args) = self.assertParseOK(["-q"],
  649. {'verbose': 0},
  650. [])
  651. self.assertTrue(options.verbose is False)
  652. def test_bool_true(self):
  653. (options, args) = self.assertParseOK(["-v"],
  654. {'verbose': 1},
  655. [])
  656. self.assertTrue(options.verbose is True)
  657. def test_bool_flicker_on_and_off(self):
  658. self.assertParseOK(["-qvq", "-q", "-v"],
  659. {'verbose': 1},
  660. [])
  661. class TestChoice(BaseTest):
  662. def setUp(self):
  663. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  664. self.parser.add_option("-c", action="store", type="choice",
  665. dest="choice", choices=["one", "two", "three"])
  666. def test_valid_choice(self):
  667. self.assertParseOK(["-c", "one", "xyz"],
  668. {'choice': 'one'},
  669. ["xyz"])
  670. def test_invalid_choice(self):
  671. self.assertParseFail(["-c", "four", "abc"],
  672. "option -c: invalid choice: 'four' "
  673. "(choose from 'one', 'two', 'three')")
  674. def test_add_choice_option(self):
  675. self.parser.add_option("-d", "--default",
  676. choices=["four", "five", "six"])
  677. opt = self.parser.get_option("-d")
  678. self.assertEqual(opt.type, "choice")
  679. self.assertEqual(opt.action, "store")
  680. class TestCount(BaseTest):
  681. def setUp(self):
  682. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  683. self.v_opt = make_option("-v", action="count", dest="verbose")
  684. self.parser.add_option(self.v_opt)
  685. self.parser.add_option("--verbose", type="int", dest="verbose")
  686. self.parser.add_option("-q", "--quiet",
  687. action="store_const", dest="verbose", const=0)
  688. def test_empty(self):
  689. self.assertParseOK([], {'verbose': None}, [])
  690. def test_count_one(self):
  691. self.assertParseOK(["-v"], {'verbose': 1}, [])
  692. def test_count_three(self):
  693. self.assertParseOK(["-vvv"], {'verbose': 3}, [])
  694. def test_count_three_apart(self):
  695. self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, [])
  696. def test_count_override_amount(self):
  697. self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, [])
  698. def test_count_override_quiet(self):
  699. self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, [])
  700. def test_count_overriding(self):
  701. self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  702. {'verbose': 1}, [])
  703. def test_count_interspersed_args(self):
  704. self.assertParseOK(["--quiet", "3", "-v"],
  705. {'verbose': 1},
  706. ["3"])
  707. def test_count_no_interspersed_args(self):
  708. self.parser.disable_interspersed_args()
  709. self.assertParseOK(["--quiet", "3", "-v"],
  710. {'verbose': 0},
  711. ["3", "-v"])
  712. def test_count_no_such_option(self):
  713. self.assertParseFail(["-q3", "-v"], "no such option: -3")
  714. def test_count_option_no_value(self):
  715. self.assertParseFail(["--quiet=3", "-v"],
  716. "--quiet option does not take a value")
  717. def test_count_with_default(self):
  718. self.parser.set_default('verbose', 0)
  719. self.assertParseOK([], {'verbose':0}, [])
  720. def test_count_overriding_default(self):
  721. self.parser.set_default('verbose', 0)
  722. self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  723. {'verbose': 1}, [])
  724. class TestMultipleArgs(BaseTest):
  725. def setUp(self):
  726. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  727. self.parser.add_option("-p", "--point",
  728. action="store", nargs=3, type="float", dest="point")
  729. def test_nargs_with_positional_args(self):
  730. self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"],
  731. {'point': (1.0, 2.5, -4.3)},
  732. ["foo", "xyz"])
  733. def test_nargs_long_opt(self):
  734. self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"],
  735. {'point': (-1.0, 2.5, -0.0)},
  736. ["xyz"])
  737. def test_nargs_invalid_float_value(self):
  738. self.assertParseFail(["-p", "1.0", "2x", "3.5"],
  739. "option -p: "
  740. "invalid floating-point value: '2x'")
  741. def test_nargs_required_values(self):
  742. self.assertParseFail(["--point", "1.0", "3.5"],
  743. "--point option requires 3 arguments")
  744. class TestMultipleArgsAppend(BaseTest):
  745. def setUp(self):
  746. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  747. self.parser.add_option("-p", "--point", action="store", nargs=3,
  748. type="float", dest="point")
  749. self.parser.add_option("-f", "--foo", action="append", nargs=2,
  750. type="int", dest="foo")
  751. self.parser.add_option("-z", "--zero", action="append_const",
  752. dest="foo", const=(0, 0))
  753. def test_nargs_append(self):
  754. self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],
  755. {'point': None, 'foo': [(4, -3), (1, 666)]},
  756. ["blah"])
  757. def test_nargs_append_required_values(self):
  758. self.assertParseFail(["-f4,3"],
  759. "-f option requires 2 arguments")
  760. def test_nargs_append_simple(self):
  761. self.assertParseOK(["--foo=3", "4"],
  762. {'point': None, 'foo':[(3, 4)]},
  763. [])
  764. def test_nargs_append_const(self):
  765. self.assertParseOK(["--zero", "--foo", "3", "4", "-z"],
  766. {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]},
  767. [])
  768. class TestVersion(BaseTest):
  769. def test_version(self):
  770. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  771. version="%prog 0.1")
  772. save_argv = sys.argv[:]
  773. try:
  774. sys.argv[0] = os.path.join(os.curdir, "foo", "bar")
  775. self.assertOutput(["--version"], "bar 0.1\n")
  776. finally:
  777. sys.argv[:] = save_argv
  778. def test_no_version(self):
  779. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  780. self.assertParseFail(["--version"],
  781. "no such option: --version")
  782. # -- Test conflicting default values and parser.parse_args() -----------
  783. class TestConflictingDefaults(BaseTest):
  784. """Conflicting default values: the last one should win."""
  785. def setUp(self):
  786. self.parser = OptionParser(option_list=[
  787. make_option("-v", action="store_true", dest="verbose", default=1)])
  788. def test_conflict_default(self):
  789. self.parser.add_option("-q", action="store_false", dest="verbose",
  790. default=0)
  791. self.assertParseOK([], {'verbose': 0}, [])
  792. def test_conflict_default_none(self):
  793. self.parser.add_option("-q", action="store_false", dest="verbose",
  794. default=None)
  795. self.assertParseOK([], {'verbose': None}, [])
  796. class TestOptionGroup(BaseTest):
  797. def setUp(self):
  798. self.parser = OptionParser(usage=SUPPRESS_USAGE)
  799. def test_option_group_create_instance(self):
  800. group = OptionGroup(self.parser, "Spam")
  801. self.parser.add_option_group(group)
  802. group.add_option("--spam", action="store_true",
  803. help="spam spam spam spam")
  804. self.assertParseOK(["--spam"], {'spam': 1}, [])
  805. def test_add_group_no_group(self):
  806. self.assertTypeError(self.parser.add_option_group,
  807. "not an OptionGroup instance: None", None)
  808. def test_add_group_invalid_arguments(self):
  809. self.assertTypeError(self.parser.add_option_group,
  810. "invalid arguments", None, None)
  811. def test_add_group_wrong_parser(self):
  812. group = OptionGroup(self.parser, "Spam")
  813. group.parser = OptionParser()
  814. self.assertRaises(self.parser.add_option_group, (group,), None,
  815. ValueError, "invalid OptionGroup (wrong parser)")
  816. def test_group_manipulate(self):
  817. group = self.parser.add_option_group("Group 2",
  818. description="Some more options")
  819. group.set_title("Bacon")
  820. group.add_option("--bacon", type="int")
  821. self.assertTrue(self.parser.get_option_group("--bacon"), group)
  822. # -- Test extending and parser.parse_args() ----------------------------
  823. class TestExtendAddTypes(BaseTest):
  824. def setUp(self):
  825. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  826. option_class=self.MyOption)
  827. self.parser.add_option("-a", None, type="string", dest="a")
  828. self.parser.add_option("-f", "--file", type="file", dest="file")
  829. def tearDown(self):
  830. if os.path.isdir(test_support.TESTFN):
  831. os.rmdir(test_support.TESTFN)
  832. elif os.path.isfile(test_support.TESTFN):
  833. os.unlink(test_support.TESTFN)
  834. class MyOption (Option):
  835. def check_file(option, opt, value):
  836. if not os.path.exists(value):
  837. raise OptionValueError("%s: file does not exist" % value)
  838. elif not os.path.isfile(value):
  839. raise OptionValueError("%s: not a regular file" % value)
  840. return value
  841. TYPES = Option.TYPES + ("file",)
  842. TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  843. TYPE_CHECKER["file"] = check_file
  844. def test_filetype_ok(self):
  845. open(test_support.TESTFN, "w").close()
  846. self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
  847. {'file': test_support.TESTFN, 'a': 'foo'},
  848. [])
  849. def test_filetype_noexist(self):
  850. self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  851. "%s: file does not exist" %
  852. test_support.TESTFN)
  853. def test_filetype_notfile(self):
  854. os.mkdir(test_support.TESTFN)
  855. self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  856. "%s: not a regular file" %
  857. test_support.TESTFN)
  858. class TestExtendAddActions(BaseTest):
  859. def setUp(self):
  860. options = [self.MyOption("-a", "--apple", action="extend",
  861. type="string", dest="apple")]
  862. self.parser = OptionParser(option_list=options)
  863. class MyOption (Option):
  864. ACTIONS = Option.ACTIONS + ("extend",)
  865. STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
  866. TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
  867. def take_action(self, action, dest, opt, value, values, parser):
  868. if action == "extend":
  869. lvalue = value.split(",")
  870. values.ensure_value(dest, []).extend(lvalue)
  871. else:
  872. Option.take_action(self, action, dest, opt, parser, value,
  873. values)
  874. def test_extend_add_action(self):
  875. self.assertParseOK(["-afoo,bar", "--apple=blah"],
  876. {'apple': ["foo", "bar", "blah"]},
  877. [])
  878. def test_extend_add_action_normal(self):
  879. self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"],
  880. {'apple': ["foo", "bar", "x", "y"]},
  881. [])
  882. # -- Test callbacks and parser.parse_args() ----------------------------
  883. class TestCallback(BaseTest):
  884. def setUp(self):
  885. options = [make_option("-x",
  886. None,
  887. action="callback",
  888. callback=self.process_opt),
  889. make_option("-f",
  890. "--file",
  891. action="callback",
  892. callback=self.process_opt,
  893. type="string",
  894. dest="filename")]
  895. self.parser = OptionParser(option_list=options)
  896. def process_opt(self, option, opt, value, parser_):
  897. if opt == "-x":
  898. self.assertEqual(option._short_opts, ["-x"])
  899. self.assertEqual(option._long_opts, [])
  900. self.assertTrue(parser_ is self.parser)
  901. self.assertTrue(value is None)
  902. self.assertEqual(vars(parser_.values), {'filename': None})
  903. parser_.values.x = 42
  904. elif opt == "--file":
  905. self.assertEqual(option._short_opts, ["-f"])
  906. self.assertEqual(option._long_opts, ["--file"])
  907. self.assertTrue(parser_ is self.parser)
  908. self.assertEqual(value, "foo")
  909. self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42})
  910. setattr(parser_.values, option.dest, value)
  911. else:
  912. self.fail("Unknown option %r in process_opt." % opt)
  913. def test_callback(self):
  914. self.assertParseOK(["-x", "--file=foo"],
  915. {'filename': "foo", 'x': 42},
  916. [])
  917. def test_callback_help(self):
  918. # This test was prompted by SF bug #960515 -- the point is
  919. # not to inspect the help text, just to make sure that
  920. # format_help() doesn't crash.
  921. parser = OptionParser(usage=SUPPRESS_USAGE)
  922. parser.remove_option("-h")
  923. parser.add_option("-t", "--test", action="callback",
  924. callback=lambda: None, type="string",
  925. help="foo")
  926. expected_help = ("Options:\n"
  927. " -t TEST, --test=TEST foo\n")
  928. self.assertHelp(parser, expected_help)
  929. class TestCallbackExtraArgs(BaseTest):
  930. def setUp(self):
  931. options = [make_option("-p", "--point", action="callback",
  932. callback=self.process_tuple,
  933. callback_args=(3, int), type="string",
  934. dest="points", default=[])]
  935. self.parser = OptionParser(option_list=options)
  936. def process_tuple(self, option, opt, value, parser_, len, type):
  937. self.assertEqual(len, 3)
  938. self.assertTrue(type is int)
  939. if opt == "-p":
  940. self.assertEqual(value, "1,2,3")
  941. elif opt == "--point":
  942. self.assertEqual(value, "4,5,6")
  943. value = tuple(map(type, value.split(",")))
  944. getattr(parser_.values, option.dest).append(value)
  945. def test_callback_extra_args(self):
  946. self.assertParseOK(["-p1,2,3", "--point", "4,5,6"],
  947. {'points': [(1,2,3), (4,5,6)]},
  948. [])
  949. class TestCallbackMeddleArgs(BaseTest):
  950. def setUp(self):
  951. options = [make_option(str(x), action="callback",
  952. callback=self.process_n, dest='things')
  953. for x in range(-1, -6, -1)]
  954. self.parser = OptionParser(option_list=options)
  955. # Callback that meddles in rargs, largs
  956. def process_n(self, option, opt, value, parser_):
  957. # option is -3, -5, etc.
  958. nargs = int(opt[1:])
  959. rargs = parser_.rargs
  960. if len(rargs) < nargs:
  961. self.fail("Expected %d arguments for %s option." % (nargs, opt))
  962. dest = parser_.values.ensure_value(option.dest, [])
  963. dest.append(tuple(rargs[0:nargs]))
  964. parser_.largs.append(nargs)
  965. del rargs[0:nargs]
  966. def test_callback_meddle_args(self):
  967. self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"],
  968. {'things': [("foo",), ("bar", "baz", "qux")]},
  969. [1, 3])
  970. def test_callback_meddle_args_separator(self):
  971. self.assertParseOK(["-2", "foo", "--"],
  972. {'things': [('foo', '--')]},
  973. [2])
  974. class TestCallbackManyArgs(BaseTest):
  975. def setUp(self):
  976. options = [make_option("-a", "--apple", action="callback", nargs=2,
  977. callback=self.process_many, type="string"),
  978. make_option("-b", "--bob", action="callback", nargs=3,
  979. callback=self.process_many, type="int")]
  980. self.parser = OptionParser(option_list=options)
  981. def process_many(self, option, opt, value, parser_):
  982. if opt == "-a":
  983. self.assertEqual(value, ("foo", "bar"))
  984. elif opt == "--apple":
  985. self.assertEqual(value, ("ding", "dong"))
  986. elif opt == "-b":
  987. self.assertEqual(value, (1, 2, 3))
  988. elif opt == "--bob":
  989. self.assertEqual(value, (-666, 42, 0))
  990. def test_many_args(self):
  991. self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
  992. "-b", "1", "2", "3", "--bob", "-666", "42",
  993. "0"],
  994. {"apple": None, "bob": None},
  995. [])
  996. class TestCallbackCheckAbbrev(BaseTest):
  997. def setUp(self):
  998. self.parser = OptionParser()
  999. self.parser.add_option("--foo-bar", action="callback",
  1000. callback=self.check_abbrev)
  1001. def check_abbrev(self, option, opt, value, parser):
  1002. self.assertEqual(opt, "--foo-bar")
  1003. def test_abbrev_callback_expansion(self):
  1004. self.assertParseOK(["--foo"], {}, [])
  1005. class TestCallbackVarArgs(BaseTest):
  1006. def setUp(self):
  1007. options = [make_option("-a", type="int", nargs=2, dest="a"),
  1008. make_option("-b", action="store_true", dest="b"),
  1009. make_option("-c", "--callback", action="callback",
  1010. callback=self.variable_args, dest="c")]
  1011. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1012. option_list=options)
  1013. def variable_args(self, option, opt, value, parser):
  1014. self.assertTrue(value is None)
  1015. value = []
  1016. rargs = parser.rargs
  1017. while rargs:
  1018. arg = rargs[0]
  1019. if ((arg[:2] == "--" and len(arg) > 2) or
  1020. (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
  1021. break
  1022. else:
  1023. value.append(arg)
  1024. del rargs[0]
  1025. setattr(parser.values, option.dest, value)
  1026. def test_variable_args(self):
  1027. self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"],
  1028. {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]},
  1029. [])
  1030. def test_consume_separator_stop_at_option(self):
  1031. self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"],
  1032. {'a': None,
  1033. 'b': True,
  1034. 'c': ["37", "--", "xxx"]},
  1035. ["hello"])
  1036. def test_positional_arg_and_variable_args(self):
  1037. self.assertParseOK(["hello", "-c", "foo", "-", "bar"],
  1038. {'a': None,
  1039. 'b': None,
  1040. 'c':["foo", "-", "bar"]},
  1041. ["hello"])
  1042. def test_stop_at_option(self):
  1043. self.assertParseOK(["-c", "foo", "-b"],
  1044. {'a': None, 'b': True, 'c': ["foo"]},
  1045. [])
  1046. def test_stop_at_invalid_option(self):
  1047. self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5")
  1048. # -- Test conflict handling and parser.parse_args() --------------------
  1049. class ConflictBase(BaseTest):
  1050. def setUp(self):
  1051. options = [make_option("-v", "--verbose", action="count",
  1052. dest="verbose", help="increment verbosity")]
  1053. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1054. option_list=options)
  1055. def show_version(self, option, opt, value, parser):
  1056. parser.values.show_version = 1
  1057. class TestConflict(ConflictBase):
  1058. """Use the default conflict resolution for Optik 1.2: error."""
  1059. def assertTrueconflict_error(self, func):
  1060. err = self.assertRaises(
  1061. func, ("-v", "--version"), {'action' : "callback",
  1062. 'callback' : self.show_version,
  1063. 'help' : "show …

Large files files are truncated, but you can click here to view the full file