PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/kcr/pypy
Python | 1620 lines | 1532 code | 67 blank | 21 comment | 22 complexity | 813094afecf410abccfb0e79075f4c53 MD5 | raw file
Possible License(s): Apache-2.0

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. @test_support.impl_detail("sys.getrefcount")
  319. def test_refleak(self):
  320. # If an OptionParser is carrying around a reference to a large
  321. # object, various cycles can prevent it from being GC'd in
  322. # a timely fashion. destroy() breaks the cycles to ensure stuff
  323. # can be cleaned up.
  324. big_thing = [42]
  325. refcount = sys.getrefcount(big_thing)
  326. parser = OptionParser()
  327. parser.add_option("-a", "--aaarggh")
  328. parser.big_thing = big_thing
  329. parser.destroy()
  330. #self.assertEqual(refcount, sys.getrefcount(big_thing))
  331. del parser
  332. self.assertEqual(refcount, sys.getrefcount(big_thing))
  333. class TestOptionValues(BaseTest):
  334. def setUp(self):
  335. pass
  336. def test_basics(self):
  337. values = Values()
  338. self.assertEqual(vars(values), {})
  339. self.assertEqual(values, {})
  340. self.assertNotEqual(values, {"foo": "bar"})
  341. self.assertNotEqual(values, "")
  342. dict = {"foo": "bar", "baz": 42}
  343. values = Values(defaults=dict)
  344. self.assertEqual(vars(values), dict)
  345. self.assertEqual(values, dict)
  346. self.assertNotEqual(values, {"foo": "bar"})
  347. self.assertNotEqual(values, {})
  348. self.assertNotEqual(values, "")
  349. self.assertNotEqual(values, [])
  350. class TestTypeAliases(BaseTest):
  351. def setUp(self):
  352. self.parser = OptionParser()
  353. def test_str_aliases_string(self):
  354. self.parser.add_option("-s", type="str")
  355. self.assertEqual(self.parser.get_option("-s").type, "string")
  356. def test_new_type_object(self):
  357. self.parser.add_option("-s", type=str)
  358. self.assertEqual(self.parser.get_option("-s").type, "string")
  359. self.parser.add_option("-x", type=int)
  360. self.assertEqual(self.parser.get_option("-x").type, "int")
  361. def test_old_type_object(self):
  362. self.parser.add_option("-s", type=types.StringType)
  363. self.assertEqual(self.parser.get_option("-s").type, "string")
  364. self.parser.add_option("-x", type=types.IntType)
  365. self.assertEqual(self.parser.get_option("-x").type, "int")
  366. # Custom type for testing processing of default values.
  367. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
  368. def _check_duration(option, opt, value):
  369. try:
  370. if value[-1].isdigit():
  371. return int(value)
  372. else:
  373. return int(value[:-1]) * _time_units[value[-1]]
  374. except (ValueError, IndexError):
  375. raise OptionValueError(
  376. 'option %s: invalid duration: %r' % (opt, value))
  377. class DurationOption(Option):
  378. TYPES = Option.TYPES + ('duration',)
  379. TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  380. TYPE_CHECKER['duration'] = _check_duration
  381. class TestDefaultValues(BaseTest):
  382. def setUp(self):
  383. self.parser = OptionParser()
  384. self.parser.add_option("-v", "--verbose", default=True)
  385. self.parser.add_option("-q", "--quiet", dest='verbose')
  386. self.parser.add_option("-n", type="int", default=37)
  387. self.parser.add_option("-m", type="int")
  388. self.parser.add_option("-s", default="foo")
  389. self.parser.add_option("-t")
  390. self.parser.add_option("-u", default=None)
  391. self.expected = { 'verbose': True,
  392. 'n': 37,
  393. 'm': None,
  394. 's': "foo",
  395. 't': None,
  396. 'u': None }
  397. def test_basic_defaults(self):
  398. self.assertEqual(self.parser.get_default_values(), self.expected)
  399. def test_mixed_defaults_post(self):
  400. self.parser.set_defaults(n=42, m=-100)
  401. self.expected.update({'n': 42, 'm': -100})
  402. self.assertEqual(self.parser.get_default_values(), self.expected)
  403. def test_mixed_defaults_pre(self):
  404. self.parser.set_defaults(x="barf", y="blah")
  405. self.parser.add_option("-x", default="frob")
  406. self.parser.add_option("-y")
  407. self.expected.update({'x': "frob", 'y': "blah"})
  408. self.assertEqual(self.parser.get_default_values(), self.expected)
  409. self.parser.remove_option("-y")
  410. self.parser.add_option("-y", default=None)
  411. self.expected.update({'y': None})
  412. self.assertEqual(self.parser.get_default_values(), self.expected)
  413. def test_process_default(self):
  414. self.parser.option_class = DurationOption
  415. self.parser.add_option("-d", type="duration", default=300)
  416. self.parser.add_option("-e", type="duration", default="6m")
  417. self.parser.set_defaults(n="42")
  418. self.expected.update({'d': 300, 'e': 360, 'n': 42})
  419. self.assertEqual(self.parser.get_default_values(), self.expected)
  420. self.parser.set_process_default_values(False)
  421. self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
  422. self.assertEqual(self.parser.get_default_values(), self.expected)
  423. class TestProgName(BaseTest):
  424. """
  425. Test that %prog expands to the right thing in usage, version,
  426. and help strings.
  427. """
  428. def assertUsage(self, parser, expected_usage):
  429. self.assertEqual(parser.get_usage(), expected_usage)
  430. def assertVersion(self, parser, expected_version):
  431. self.assertEqual(parser.get_version(), expected_version)
  432. def test_default_progname(self):
  433. # Make sure that program name taken from sys.argv[0] by default.
  434. save_argv = sys.argv[:]
  435. try:
  436. sys.argv[0] = os.path.join("foo", "bar", "baz.py")
  437. parser = OptionParser("%prog ...", version="%prog 1.2")
  438. expected_usage = "Usage: baz.py ...\n"
  439. self.assertUsage(parser, expected_usage)
  440. self.assertVersion(parser, "baz.py 1.2")
  441. self.assertHelp(parser,
  442. expected_usage + "\n" +
  443. "Options:\n"
  444. " --version show program's version number and exit\n"
  445. " -h, --help show this help message and exit\n")
  446. finally:
  447. sys.argv[:] = save_argv
  448. def test_custom_progname(self):
  449. parser = OptionParser(prog="thingy",
  450. version="%prog 0.1",
  451. usage="%prog arg arg")
  452. parser.remove_option("-h")
  453. parser.remove_option("--version")
  454. expected_usage = "Usage: thingy arg arg\n"
  455. self.assertUsage(parser, expected_usage)
  456. self.assertVersion(parser, "thingy 0.1")
  457. self.assertHelp(parser, expected_usage + "\n")
  458. class TestExpandDefaults(BaseTest):
  459. def setUp(self):
  460. self.parser = OptionParser(prog="test")
  461. self.help_prefix = """\
  462. Usage: test [options]
  463. Options:
  464. -h, --help show this help message and exit
  465. """
  466. self.file_help = "read from FILE [default: %default]"
  467. self.expected_help_file = self.help_prefix + \
  468. " -f FILE, --file=FILE read from FILE [default: foo.txt]\n"
  469. self.expected_help_none = self.help_prefix + \
  470. " -f FILE, --file=FILE read from FILE [default: none]\n"
  471. def test_option_default(self):
  472. self.parser.add_option("-f", "--file",
  473. default="foo.txt",
  474. help=self.file_help)
  475. self.assertHelp(self.parser, self.expected_help_file)
  476. def test_parser_default_1(self):
  477. self.parser.add_option("-f", "--file",
  478. help=self.file_help)
  479. self.parser.set_default('file', "foo.txt")
  480. self.assertHelp(self.parser, self.expected_help_file)
  481. def test_parser_default_2(self):
  482. self.parser.add_option("-f", "--file",
  483. help=self.file_help)
  484. self.parser.set_defaults(file="foo.txt")
  485. self.assertHelp(self.parser, self.expected_help_file)
  486. def test_no_default(self):
  487. self.parser.add_option("-f", "--file",
  488. help=self.file_help)
  489. self.assertHelp(self.parser, self.expected_help_none)
  490. def test_default_none_1(self):
  491. self.parser.add_option("-f", "--file",
  492. default=None,
  493. help=self.file_help)
  494. self.assertHelp(self.parser, self.expected_help_none)
  495. def test_default_none_2(self):
  496. self.parser.add_option("-f", "--file",
  497. help=self.file_help)
  498. self.parser.set_defaults(file=None)
  499. self.assertHelp(self.parser, self.expected_help_none)
  500. def test_float_default(self):
  501. self.parser.add_option(
  502. "-p", "--prob",
  503. help="blow up with probability PROB [default: %default]")
  504. self.parser.set_defaults(prob=0.43)
  505. expected_help = self.help_prefix + \
  506. " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n"
  507. self.assertHelp(self.parser, expected_help)
  508. def test_alt_expand(self):
  509. self.parser.add_option("-f", "--file",
  510. default="foo.txt",
  511. help="read from FILE [default: *DEFAULT*]")
  512. self.parser.formatter.default_tag = "*DEFAULT*"
  513. self.assertHelp(self.parser, self.expected_help_file)
  514. def test_no_expand(self):
  515. self.parser.add_option("-f", "--file",
  516. default="foo.txt",
  517. help="read from %default file")
  518. self.parser.formatter.default_tag = None
  519. expected_help = self.help_prefix + \
  520. " -f FILE, --file=FILE read from %default file\n"
  521. self.assertHelp(self.parser, expected_help)
  522. # -- Test parser.parse_args() ------------------------------------------
  523. class TestStandard(BaseTest):
  524. def setUp(self):
  525. options = [make_option("-a", type="string"),
  526. make_option("-b", "--boo", type="int", dest='boo'),
  527. make_option("--foo", action="append")]
  528. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  529. option_list=options)
  530. def test_required_value(self):
  531. self.assertParseFail(["-a"], "-a option requires an argument")
  532. def test_invalid_integer(self):
  533. self.assertParseFail(["-b", "5x"],
  534. "option -b: invalid integer value: '5x'")
  535. def test_no_such_option(self):
  536. self.assertParseFail(["--boo13"], "no such option: --boo13")
  537. def test_long_invalid_integer(self):
  538. self.assertParseFail(["--boo=x5"],
  539. "option --boo: invalid integer value: 'x5'")
  540. def test_empty(self):
  541. self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
  542. def test_shortopt_empty_longopt_append(self):
  543. self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
  544. {'a': "", 'boo': None, 'foo': ["blah", ""]},
  545. [])
  546. def test_long_option_append(self):
  547. self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
  548. {'a': None,
  549. 'boo': None,
  550. 'foo': ["bar", "", "x"]},
  551. [])
  552. def test_option_argument_joined(self):
  553. self.assertParseOK(["-abc"],
  554. {'a': "bc", 'boo': None, 'foo': None},
  555. [])
  556. def test_option_argument_split(self):
  557. self.assertParseOK(["-a", "34"],
  558. {'a': "34", 'boo': None, 'foo': None},
  559. [])
  560. def test_option_argument_joined_integer(self):
  561. self.assertParseOK(["-b34"],
  562. {'a': None, 'boo': 34, 'foo': None},
  563. [])
  564. def test_option_argument_split_negative_integer(self):
  565. self.assertParseOK(["-b", "-5"],
  566. {'a': None, 'boo': -5, 'foo': None},
  567. [])
  568. def test_long_option_argument_joined(self):
  569. self.assertParseOK(["--boo=13"],
  570. {'a': None, 'boo': 13, 'foo': None},
  571. [])
  572. def test_long_option_argument_split(self):
  573. self.assertParseOK(["--boo", "111"],
  574. {'a': None, 'boo': 111, 'foo': None},
  575. [])
  576. def test_long_option_short_option(self):
  577. self.assertParseOK(["--foo=bar", "-axyz"],
  578. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  579. [])
  580. def test_abbrev_long_option(self):
  581. self.assertParseOK(["--f=bar", "-axyz"],
  582. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  583. [])
  584. def test_defaults(self):
  585. (options, args) = self.parser.parse_args([])
  586. defaults = self.parser.get_default_values()
  587. self.assertEqual(vars(defaults), vars(options))
  588. def test_ambiguous_option(self):
  589. self.parser.add_option("--foz", action="store",
  590. type="string", dest="foo")
  591. self.assertParseFail(["--f=bar"],
  592. "ambiguous option: --f (--foo, --foz?)")
  593. def test_short_and_long_option_split(self):
  594. self.assertParseOK(["-a", "xyz", "--foo", "bar"],
  595. {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
  596. []),
  597. def test_short_option_split_long_option_append(self):
  598. self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
  599. {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
  600. [])
  601. def test_short_option_split_one_positional_arg(self):
  602. self.assertParseOK(["-a", "foo", "bar"],
  603. {'a': "foo", 'boo': None, 'foo': None},
  604. ["bar"]),
  605. def test_short_option_consumes_separator(self):
  606. self.assertParseOK(["-a", "--", "foo", "bar"],
  607. {'a': "--", 'boo': None, 'foo': None},
  608. ["foo", "bar"]),
  609. self.assertParseOK(["-a", "--", "--foo", "bar"],
  610. {'a': "--", 'boo': None, 'foo': ["bar"]},
  611. []),
  612. def test_short_option_joined_and_separator(self):
  613. self.assertParseOK(["-ab", "--", "--foo", "bar"],
  614. {'a': "b", 'boo': None, 'foo': None},
  615. ["--foo", "bar"]),
  616. def test_hyphen_becomes_positional_arg(self):
  617. self.assertParseOK(["-ab", "-", "--foo", "bar"],
  618. {'a': "b", 'boo': None, 'foo': ["bar"]},
  619. ["-"])
  620. def test_no_append_versus_append(self):
  621. self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
  622. {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
  623. [])
  624. def test_option_consumes_optionlike_string(self):
  625. self.assertParseOK(["-a", "-b3"],
  626. {'a': "-b3", 'boo': None, 'foo': None},
  627. [])
  628. def test_combined_single_invalid_option(self):
  629. self.parser.add_option("-t", action="store_true")
  630. self.assertParseFail(["-test"],
  631. "no such option: -e")
  632. class TestBool(BaseTest):
  633. def setUp(self):
  634. options = [make_option("-v",
  635. "--verbose",
  636. action="store_true",
  637. dest="verbose",
  638. default=''),
  639. make_option("-q",
  640. "--quiet",
  641. action="store_false",
  642. dest="verbose")]
  643. self.parser = OptionParser(option_list = options)
  644. def test_bool_default(self):
  645. self.assertParseOK([],
  646. {'verbose': ''},
  647. [])
  648. def test_bool_false(self):
  649. (options, args) = self.assertParseOK(["-q"],
  650. {'verbose': 0},
  651. [])
  652. self.assertTrue(options.verbose is False)
  653. def test_bool_true(self):
  654. (options, args) = self.assertParseOK(["-v"],
  655. {'verbose': 1},
  656. [])
  657. self.assertTrue(options.verbose is True)
  658. def test_bool_flicker_on_and_off(self):
  659. self.assertParseOK(["-qvq", "-q", "-v"],
  660. {'verbose': 1},
  661. [])
  662. class TestChoice(BaseTest):
  663. def setUp(self):
  664. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  665. self.parser.add_option("-c", action="store", type="choice",
  666. dest="choice", choices=["one", "two", "three"])
  667. def test_valid_choice(self):
  668. self.assertParseOK(["-c", "one", "xyz"],
  669. {'choice': 'one'},
  670. ["xyz"])
  671. def test_invalid_choice(self):
  672. self.assertParseFail(["-c", "four", "abc"],
  673. "option -c: invalid choice: 'four' "
  674. "(choose from 'one', 'two', 'three')")
  675. def test_add_choice_option(self):
  676. self.parser.add_option("-d", "--default",
  677. choices=["four", "five", "six"])
  678. opt = self.parser.get_option("-d")
  679. self.assertEqual(opt.type, "choice")
  680. self.assertEqual(opt.action, "store")
  681. class TestCount(BaseTest):
  682. def setUp(self):
  683. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  684. self.v_opt = make_option("-v", action="count", dest="verbose")
  685. self.parser.add_option(self.v_opt)
  686. self.parser.add_option("--verbose", type="int", dest="verbose")
  687. self.parser.add_option("-q", "--quiet",
  688. action="store_const", dest="verbose", const=0)
  689. def test_empty(self):
  690. self.assertParseOK([], {'verbose': None}, [])
  691. def test_count_one(self):
  692. self.assertParseOK(["-v"], {'verbose': 1}, [])
  693. def test_count_three(self):
  694. self.assertParseOK(["-vvv"], {'verbose': 3}, [])
  695. def test_count_three_apart(self):
  696. self.assertParseOK(["-v", "-v", "-v"], {'verbose': 3}, [])
  697. def test_count_override_amount(self):
  698. self.assertParseOK(["-vvv", "--verbose=2"], {'verbose': 2}, [])
  699. def test_count_override_quiet(self):
  700. self.assertParseOK(["-vvv", "--verbose=2", "-q"], {'verbose': 0}, [])
  701. def test_count_overriding(self):
  702. self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  703. {'verbose': 1}, [])
  704. def test_count_interspersed_args(self):
  705. self.assertParseOK(["--quiet", "3", "-v"],
  706. {'verbose': 1},
  707. ["3"])
  708. def test_count_no_interspersed_args(self):
  709. self.parser.disable_interspersed_args()
  710. self.assertParseOK(["--quiet", "3", "-v"],
  711. {'verbose': 0},
  712. ["3", "-v"])
  713. def test_count_no_such_option(self):
  714. self.assertParseFail(["-q3", "-v"], "no such option: -3")
  715. def test_count_option_no_value(self):
  716. self.assertParseFail(["--quiet=3", "-v"],
  717. "--quiet option does not take a value")
  718. def test_count_with_default(self):
  719. self.parser.set_default('verbose', 0)
  720. self.assertParseOK([], {'verbose':0}, [])
  721. def test_count_overriding_default(self):
  722. self.parser.set_default('verbose', 0)
  723. self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"],
  724. {'verbose': 1}, [])
  725. class TestMultipleArgs(BaseTest):
  726. def setUp(self):
  727. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  728. self.parser.add_option("-p", "--point",
  729. action="store", nargs=3, type="float", dest="point")
  730. def test_nargs_with_positional_args(self):
  731. self.assertParseOK(["foo", "-p", "1", "2.5", "-4.3", "xyz"],
  732. {'point': (1.0, 2.5, -4.3)},
  733. ["foo", "xyz"])
  734. def test_nargs_long_opt(self):
  735. self.assertParseOK(["--point", "-1", "2.5", "-0", "xyz"],
  736. {'point': (-1.0, 2.5, -0.0)},
  737. ["xyz"])
  738. def test_nargs_invalid_float_value(self):
  739. self.assertParseFail(["-p", "1.0", "2x", "3.5"],
  740. "option -p: "
  741. "invalid floating-point value: '2x'")
  742. def test_nargs_required_values(self):
  743. self.assertParseFail(["--point", "1.0", "3.5"],
  744. "--point option requires 3 arguments")
  745. class TestMultipleArgsAppend(BaseTest):
  746. def setUp(self):
  747. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  748. self.parser.add_option("-p", "--point", action="store", nargs=3,
  749. type="float", dest="point")
  750. self.parser.add_option("-f", "--foo", action="append", nargs=2,
  751. type="int", dest="foo")
  752. self.parser.add_option("-z", "--zero", action="append_const",
  753. dest="foo", const=(0, 0))
  754. def test_nargs_append(self):
  755. self.assertParseOK(["-f", "4", "-3", "blah", "--foo", "1", "666"],
  756. {'point': None, 'foo': [(4, -3), (1, 666)]},
  757. ["blah"])
  758. def test_nargs_append_required_values(self):
  759. self.assertParseFail(["-f4,3"],
  760. "-f option requires 2 arguments")
  761. def test_nargs_append_simple(self):
  762. self.assertParseOK(["--foo=3", "4"],
  763. {'point': None, 'foo':[(3, 4)]},
  764. [])
  765. def test_nargs_append_const(self):
  766. self.assertParseOK(["--zero", "--foo", "3", "4", "-z"],
  767. {'point': None, 'foo':[(0, 0), (3, 4), (0, 0)]},
  768. [])
  769. class TestVersion(BaseTest):
  770. def test_version(self):
  771. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  772. version="%prog 0.1")
  773. save_argv = sys.argv[:]
  774. try:
  775. sys.argv[0] = os.path.join(os.curdir, "foo", "bar")
  776. self.assertOutput(["--version"], "bar 0.1\n")
  777. finally:
  778. sys.argv[:] = save_argv
  779. def test_no_version(self):
  780. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
  781. self.assertParseFail(["--version"],
  782. "no such option: --version")
  783. # -- Test conflicting default values and parser.parse_args() -----------
  784. class TestConflictingDefaults(BaseTest):
  785. """Conflicting default values: the last one should win."""
  786. def setUp(self):
  787. self.parser = OptionParser(option_list=[
  788. make_option("-v", action="store_true", dest="verbose", default=1)])
  789. def test_conflict_default(self):
  790. self.parser.add_option("-q", action="store_false", dest="verbose",
  791. default=0)
  792. self.assertParseOK([], {'verbose': 0}, [])
  793. def test_conflict_default_none(self):
  794. self.parser.add_option("-q", action="store_false", dest="verbose",
  795. default=None)
  796. self.assertParseOK([], {'verbose': None}, [])
  797. class TestOptionGroup(BaseTest):
  798. def setUp(self):
  799. self.parser = OptionParser(usage=SUPPRESS_USAGE)
  800. def test_option_group_create_instance(self):
  801. group = OptionGroup(self.parser, "Spam")
  802. self.parser.add_option_group(group)
  803. group.add_option("--spam", action="store_true",
  804. help="spam spam spam spam")
  805. self.assertParseOK(["--spam"], {'spam': 1}, [])
  806. def test_add_group_no_group(self):
  807. self.assertTypeError(self.parser.add_option_group,
  808. "not an OptionGroup instance: None", None)
  809. def test_add_group_invalid_arguments(self):
  810. self.assertTypeError(self.parser.add_option_group,
  811. "invalid arguments", None, None)
  812. def test_add_group_wrong_parser(self):
  813. group = OptionGroup(self.parser, "Spam")
  814. group.parser = OptionParser()
  815. self.assertRaises(self.parser.add_option_group, (group,), None,
  816. ValueError, "invalid OptionGroup (wrong parser)")
  817. def test_group_manipulate(self):
  818. group = self.parser.add_option_group("Group 2",
  819. description="Some more options")
  820. group.set_title("Bacon")
  821. group.add_option("--bacon", type="int")
  822. self.assertTrue(self.parser.get_option_group("--bacon"), group)
  823. # -- Test extending and parser.parse_args() ----------------------------
  824. class TestExtendAddTypes(BaseTest):
  825. def setUp(self):
  826. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  827. option_class=self.MyOption)
  828. self.parser.add_option("-a", None, type="string", dest="a")
  829. self.parser.add_option("-f", "--file", type="file", dest="file")
  830. def tearDown(self):
  831. if os.path.isdir(test_support.TESTFN):
  832. os.rmdir(test_support.TESTFN)
  833. elif os.path.isfile(test_support.TESTFN):
  834. os.unlink(test_support.TESTFN)
  835. class MyOption (Option):
  836. def check_file(option, opt, value):
  837. if not os.path.exists(value):
  838. raise OptionValueError("%s: file does not exist" % value)
  839. elif not os.path.isfile(value):
  840. raise OptionValueError("%s: not a regular file" % value)
  841. return value
  842. TYPES = Option.TYPES + ("file",)
  843. TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
  844. TYPE_CHECKER["file"] = check_file
  845. def test_filetype_ok(self):
  846. open(test_support.TESTFN, "w").close()
  847. self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
  848. {'file': test_support.TESTFN, 'a': 'foo'},
  849. [])
  850. def test_filetype_noexist(self):
  851. self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  852. "%s: file does not exist" %
  853. test_support.TESTFN)
  854. def test_filetype_notfile(self):
  855. os.mkdir(test_support.TESTFN)
  856. self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
  857. "%s: not a regular file" %
  858. test_support.TESTFN)
  859. class TestExtendAddActions(BaseTest):
  860. def setUp(self):
  861. options = [self.MyOption("-a", "--apple", action="extend",
  862. type="string", dest="apple")]
  863. self.parser = OptionParser(option_list=options)
  864. class MyOption (Option):
  865. ACTIONS = Option.ACTIONS + ("extend",)
  866. STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
  867. TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
  868. def take_action(self, action, dest, opt, value, values, parser):
  869. if action == "extend":
  870. lvalue = value.split(",")
  871. values.ensure_value(dest, []).extend(lvalue)
  872. else:
  873. Option.take_action(self, action, dest, opt, parser, value,
  874. values)
  875. def test_extend_add_action(self):
  876. self.assertParseOK(["-afoo,bar", "--apple=blah"],
  877. {'apple': ["foo", "bar", "blah"]},
  878. [])
  879. def test_extend_add_action_normal(self):
  880. self.assertParseOK(["-a", "foo", "-abar", "--apple=x,y"],
  881. {'apple': ["foo", "bar", "x", "y"]},
  882. [])
  883. # -- Test callbacks and parser.parse_args() ----------------------------
  884. class TestCallback(BaseTest):
  885. def setUp(self):
  886. options = [make_option("-x",
  887. None,
  888. action="callback",
  889. callback=self.process_opt),
  890. make_option("-f",
  891. "--file",
  892. action="callback",
  893. callback=self.process_opt,
  894. type="string",
  895. dest="filename")]
  896. self.parser = OptionParser(option_list=options)
  897. def process_opt(self, option, opt, value, parser_):
  898. if opt == "-x":
  899. self.assertEqual(option._short_opts, ["-x"])
  900. self.assertEqual(option._long_opts, [])
  901. self.assertTrue(parser_ is self.parser)
  902. self.assertTrue(value is None)
  903. self.assertEqual(vars(parser_.values), {'filename': None})
  904. parser_.values.x = 42
  905. elif opt == "--file":
  906. self.assertEqual(option._short_opts, ["-f"])
  907. self.assertEqual(option._long_opts, ["--file"])
  908. self.assertTrue(parser_ is self.parser)
  909. self.assertEqual(value, "foo")
  910. self.assertEqual(vars(parser_.values), {'filename': None, 'x': 42})
  911. setattr(parser_.values, option.dest, value)
  912. else:
  913. self.fail("Unknown option %r in process_opt." % opt)
  914. def test_callback(self):
  915. self.assertParseOK(["-x", "--file=foo"],
  916. {'filename': "foo", 'x': 42},
  917. [])
  918. def test_callback_help(self):
  919. # This test was prompted by SF bug #960515 -- the point is
  920. # not to inspect the help text, just to make sure that
  921. # format_help() doesn't crash.
  922. parser = OptionParser(usage=SUPPRESS_USAGE)
  923. parser.remove_option("-h")
  924. parser.add_option("-t", "--test", action="callback",
  925. callback=lambda: None, type="string",
  926. help="foo")
  927. expected_help = ("Options:\n"
  928. " -t TEST, --test=TEST foo\n")
  929. self.assertHelp(parser, expected_help)
  930. class TestCallbackExtraArgs(BaseTest):
  931. def setUp(self):
  932. options = [make_option("-p", "--point", action="callback",
  933. callback=self.process_tuple,
  934. callback_args=(3, int), type="string",
  935. dest="points", default=[])]
  936. self.parser = OptionParser(option_list=options)
  937. def process_tuple(self, option, opt, value, parser_, len, type):
  938. self.assertEqual(len, 3)
  939. self.assertTrue(type is int)
  940. if opt == "-p":
  941. self.assertEqual(value, "1,2,3")
  942. elif opt == "--point":
  943. self.assertEqual(value, "4,5,6")
  944. value = tuple(map(type, value.split(",")))
  945. getattr(parser_.values, option.dest).append(value)
  946. def test_callback_extra_args(self):
  947. self.assertParseOK(["-p1,2,3", "--point", "4,5,6"],
  948. {'points': [(1,2,3), (4,5,6)]},
  949. [])
  950. class TestCallbackMeddleArgs(BaseTest):
  951. def setUp(self):
  952. options = [make_option(str(x), action="callback",
  953. callback=self.process_n, dest='things')
  954. for x in range(-1, -6, -1)]
  955. self.parser = OptionParser(option_list=options)
  956. # Callback that meddles in rargs, largs
  957. def process_n(self, option, opt, value, parser_):
  958. # option is -3, -5, etc.
  959. nargs = int(opt[1:])
  960. rargs = parser_.rargs
  961. if len(rargs) < nargs:
  962. self.fail("Expected %d arguments for %s option." % (nargs, opt))
  963. dest = parser_.values.ensure_value(option.dest, [])
  964. dest.append(tuple(rargs[0:nargs]))
  965. parser_.largs.append(nargs)
  966. del rargs[0:nargs]
  967. def test_callback_meddle_args(self):
  968. self.assertParseOK(["-1", "foo", "-3", "bar", "baz", "qux"],
  969. {'things': [("foo",), ("bar", "baz", "qux")]},
  970. [1, 3])
  971. def test_callback_meddle_args_separator(self):
  972. self.assertParseOK(["-2", "foo", "--"],
  973. {'things': [('foo', '--')]},
  974. [2])
  975. class TestCallbackManyArgs(BaseTest):
  976. def setUp(self):
  977. options = [make_option("-a", "--apple", action="callback", nargs=2,
  978. callback=self.process_many, type="string"),
  979. make_option("-b", "--bob", action="callback", nargs=3,
  980. callback=self.process_many, type="int")]
  981. self.parser = OptionParser(option_list=options)
  982. def process_many(self, option, opt, value, parser_):
  983. if opt == "-a":
  984. self.assertEqual(value, ("foo", "bar"))
  985. elif opt == "--apple":
  986. self.assertEqual(value, ("ding", "dong"))
  987. elif opt == "-b":
  988. self.assertEqual(value, (1, 2, 3))
  989. elif opt == "--bob":
  990. self.assertEqual(value, (-666, 42, 0))
  991. def test_many_args(self):
  992. self.assertParseOK(["-a", "foo", "bar", "--apple", "ding", "dong",
  993. "-b", "1", "2", "3", "--bob", "-666", "42",
  994. "0"],
  995. {"apple": None, "bob": None},
  996. [])
  997. class TestCallbackCheckAbbrev(BaseTest):
  998. def setUp(self):
  999. self.parser = OptionParser()
  1000. self.parser.add_option("--foo-bar", action="callback",
  1001. callback=self.check_abbrev)
  1002. def check_abbrev(self, option, opt, value, parser):
  1003. self.assertEqual(opt, "--foo-bar")
  1004. def test_abbrev_callback_expansion(self):
  1005. self.assertParseOK(["--foo"], {}, [])
  1006. class TestCallbackVarArgs(BaseTest):
  1007. def setUp(self):
  1008. options = [make_option("-a", type="int", nargs=2, dest="a"),
  1009. make_option("-b", action="store_true", dest="b"),
  1010. make_option("-c", "--callback", action="callback",
  1011. callback=self.variable_args, dest="c")]
  1012. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1013. option_list=options)
  1014. def variable_args(self, option, opt, value, parser):
  1015. self.assertTrue(value is None)
  1016. value = []
  1017. rargs = parser.rargs
  1018. while rargs:
  1019. arg = rargs[0]
  1020. if ((arg[:2] == "--" and len(arg) > 2) or
  1021. (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
  1022. break
  1023. else:
  1024. value.append(arg)
  1025. del rargs[0]
  1026. setattr(parser.values, option.dest, value)
  1027. def test_variable_args(self):
  1028. self.assertParseOK(["-a3", "-5", "--callback", "foo", "bar"],
  1029. {'a': (3, -5), 'b': None, 'c': ["foo", "bar"]},
  1030. [])
  1031. def test_consume_separator_stop_at_option(self):
  1032. self.assertParseOK(["-c", "37", "--", "xxx", "-b", "hello"],
  1033. {'a': None,
  1034. 'b': True,
  1035. 'c': ["37", "--", "xxx"]},
  1036. ["hello"])
  1037. def test_positional_arg_and_variable_args(self):
  1038. self.assertParseOK(["hello", "-c", "foo", "-", "bar"],
  1039. {'a': None,
  1040. 'b': None,
  1041. 'c':["foo", "-", "bar"]},
  1042. ["hello"])
  1043. def test_stop_at_option(self):
  1044. self.assertParseOK(["-c", "foo", "-b"],
  1045. {'a': None, 'b': True, 'c': ["foo"]},
  1046. [])
  1047. def test_stop_at_invalid_option(self):
  1048. self.assertParseFail(["-c", "3", "-5", "-a"], "no such option: -5")
  1049. # -- Test conflict handling and parser.parse_args() --------------------
  1050. class ConflictBase(BaseTest):
  1051. def setUp(self):
  1052. options = [make_option("-v", "--verbose", action="count",
  1053. dest="verbose", help="increment verbosity")]
  1054. self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
  1055. option_list=options)
  1056. def show_version(self, option, opt, value, parser):
  1057. parser.values.show_version = 1
  1058. class TestConflict(ConflictBase):
  1059. """Use the default conflict resolution for Optik 1.2: error."""
  1060. def assertTrueconflict_error(self, func):
  1061. err = self.assertRaises(
  1062. func, ("-v", "--version"), {'action' : "callback",
  1063. 'callback' : self.show_version,

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