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 |
|
---|
9 | import sys
|
---|
10 | import os
|
---|
11 | import re
|
---|
12 | import copy
|
---|
13 | import types
|
---|
14 | import unittest
|
---|
15 |
|
---|
16 | from StringIO import StringIO
|
---|
17 | from test import test_support
|
---|
18 |
|
---|
19 |
|
---|
20 | from optparse import make_option, Option, \
|
---|
21 | TitledHelpFormatter, OptionParser, OptionGroup, \
|
---|
22 | SUPPRESS_USAGE, OptionError, OptionConflictError, \
|
---|
23 | BadOptionError, OptionValueError, Values
|
---|
24 | from optparse import _match_abbrev
|
---|
25 | from optparse import _parse_num
|
---|
26 |
|
---|
27 | retype = type(re.compile(''))
|
---|
28 |
|
---|
29 | class InterceptedError(Exception):
|
---|
30 | def __init__(self,
|
---|
31 | error_message=None,
|
---|
32 | exit_status=None,
|
---|
33 | exit_message=None):
|
---|
34 | self.error_message = error_message
|
---|
35 | self.exit_status = exit_status
|
---|
36 | self.exit_message = exit_message
|
---|
37 |
|
---|
38 | def __str__(self):
|
---|
39 | return self.error_message or self.exit_message or "intercepted error"
|
---|
40 |
|
---|
41 | class InterceptingOptionParser(OptionParser):
|
---|
42 | def exit(self, status=0, msg=None):
|
---|
43 | raise InterceptedError(exit_status=status, exit_message=msg)
|
---|
44 |
|
---|
45 | def error(self, msg):
|
---|
46 | raise InterceptedError(error_message=msg)
|
---|
47 |
|
---|
48 |
|
---|
49 | class BaseTest(unittest.TestCase):
|
---|
50 | def assertParseOK(self, args, expected_opts, expected_positional_args):
|
---|
51 | """Assert the options are what we expected when parsing arguments.
|
---|
52 |
|
---|
53 | Otherwise, fail with a nicely formatted message.
|
---|
54 |
|
---|
55 | Keyword arguments:
|
---|
56 | args -- A list of arguments to parse with OptionParser.
|
---|
57 | expected_opts -- The options expected.
|
---|
58 | expected_positional_args -- The positional arguments expected.
|
---|
59 |
|
---|
60 | Returns the options and positional args for further testing.
|
---|
61 | """
|
---|
62 |
|
---|
63 | (options, positional_args) = self.parser.parse_args(args)
|
---|
64 | optdict = vars(options)
|
---|
65 |
|
---|
66 | self.assertEqual(optdict, expected_opts,
|
---|
67 | """
|
---|
68 | Options are %(optdict)s.
|
---|
69 | Should be %(expected_opts)s.
|
---|
70 | Args were %(args)s.""" % locals())
|
---|
71 |
|
---|
72 | self.assertEqual(positional_args, expected_positional_args,
|
---|
73 | """
|
---|
74 | Positional arguments are %(positional_args)s.
|
---|
75 | Should be %(expected_positional_args)s.
|
---|
76 | Args were %(args)s.""" % locals ())
|
---|
77 |
|
---|
78 | return (options, positional_args)
|
---|
79 |
|
---|
80 | def assertRaises(self,
|
---|
81 | func,
|
---|
82 | args,
|
---|
83 | kwargs,
|
---|
84 | expected_exception,
|
---|
85 | expected_message):
|
---|
86 | """
|
---|
87 | Assert that the expected exception is raised when calling a
|
---|
88 | function, and that the right error message is included with
|
---|
89 | that exception.
|
---|
90 |
|
---|
91 | Arguments:
|
---|
92 | func -- the function to call
|
---|
93 | args -- positional arguments to `func`
|
---|
94 | kwargs -- keyword arguments to `func`
|
---|
95 | expected_exception -- exception that should be raised
|
---|
96 | expected_message -- expected exception message (or pattern
|
---|
97 | if a compiled regex object)
|
---|
98 |
|
---|
99 | Returns the exception raised for further testing.
|
---|
100 | """
|
---|
101 | if args is None:
|
---|
102 | args = ()
|
---|
103 | if kwargs is None:
|
---|
104 | kwargs = {}
|
---|
105 |
|
---|
106 | try:
|
---|
107 | func(*args, **kwargs)
|
---|
108 | except expected_exception, err:
|
---|
109 | actual_message = str(err)
|
---|
110 | if isinstance(expected_message, retype):
|
---|
111 | self.assertTrue(expected_message.search(actual_message),
|
---|
112 | """\
|
---|
113 | expected exception message pattern:
|
---|
114 | /%s/
|
---|
115 | actual exception message:
|
---|
116 | '''%s'''
|
---|
117 | """ % (expected_message.pattern, actual_message))
|
---|
118 | else:
|
---|
119 | self.assertEqual(actual_message,
|
---|
120 | expected_message,
|
---|
121 | """\
|
---|
122 | expected exception message:
|
---|
123 | '''%s'''
|
---|
124 | actual exception message:
|
---|
125 | '''%s'''
|
---|
126 | """ % (expected_message, actual_message))
|
---|
127 |
|
---|
128 | return err
|
---|
129 | else:
|
---|
130 | self.fail("""expected exception %(expected_exception)s not raised
|
---|
131 | called %(func)r
|
---|
132 | with args %(args)r
|
---|
133 | and kwargs %(kwargs)r
|
---|
134 | """ % locals ())
|
---|
135 |
|
---|
136 |
|
---|
137 | # -- Assertions used in more than one class --------------------
|
---|
138 |
|
---|
139 | def assertParseFail(self, cmdline_args, expected_output):
|
---|
140 | """
|
---|
141 | Assert the parser fails with the expected message. Caller
|
---|
142 | must ensure that self.parser is an InterceptingOptionParser.
|
---|
143 | """
|
---|
144 | try:
|
---|
145 | self.parser.parse_args(cmdline_args)
|
---|
146 | except InterceptedError, err:
|
---|
147 | self.assertEqual(err.error_message, expected_output)
|
---|
148 | else:
|
---|
149 | self.assertFalse("expected parse failure")
|
---|
150 |
|
---|
151 | def assertOutput(self,
|
---|
152 | cmdline_args,
|
---|
153 | expected_output,
|
---|
154 | expected_status=0,
|
---|
155 | expected_error=None):
|
---|
156 | """Assert the parser prints the expected output on stdout."""
|
---|
157 | save_stdout = sys.stdout
|
---|
158 | encoding = getattr(save_stdout, 'encoding', None)
|
---|
159 | try:
|
---|
160 | try:
|
---|
161 | sys.stdout = StringIO()
|
---|
162 | if encoding:
|
---|
163 | sys.stdout.encoding = encoding
|
---|
164 | self.parser.parse_args(cmdline_args)
|
---|
165 | finally:
|
---|
166 | output = sys.stdout.getvalue()
|
---|
167 | sys.stdout = save_stdout
|
---|
168 |
|
---|
169 | except InterceptedError, err:
|
---|
170 | self.assertTrue(
|
---|
171 | type(output) is types.StringType,
|
---|
172 | "expected output to be an ordinary string, not %r"
|
---|
173 | % type(output))
|
---|
174 |
|
---|
175 | if output != expected_output:
|
---|
176 | self.fail("expected: \n'''\n" + expected_output +
|
---|
177 | "'''\nbut got \n'''\n" + output + "'''")
|
---|
178 | self.assertEqual(err.exit_status, expected_status)
|
---|
179 | self.assertEqual(err.exit_message, expected_error)
|
---|
180 | else:
|
---|
181 | self.assertFalse("expected parser.exit()")
|
---|
182 |
|
---|
183 | def assertTypeError(self, func, expected_message, *args):
|
---|
184 | """Assert that TypeError is raised when executing func."""
|
---|
185 | self.assertRaises(func, args, None, TypeError, expected_message)
|
---|
186 |
|
---|
187 | def assertHelp(self, parser, expected_help):
|
---|
188 | actual_help = parser.format_help()
|
---|
189 | if actual_help != expected_help:
|
---|
190 | raise self.failureException(
|
---|
191 | 'help text failure; expected:\n"' +
|
---|
192 | expected_help + '"; got:\n"' +
|
---|
193 | actual_help + '"\n')
|
---|
194 |
|
---|
195 | # -- Test make_option() aka Option -------------------------------------
|
---|
196 |
|
---|
197 | # It's not necessary to test correct options here. All the tests in the
|
---|
198 | # parser.parse_args() section deal with those, because they're needed
|
---|
199 | # there.
|
---|
200 |
|
---|
201 | class TestOptionChecks(BaseTest):
|
---|
202 | def setUp(self):
|
---|
203 | self.parser = OptionParser(usage=SUPPRESS_USAGE)
|
---|
204 |
|
---|
205 | def assertOptionError(self, expected_message, args=[], kwargs={}):
|
---|
206 | self.assertRaises(make_option, args, kwargs,
|
---|
207 | OptionError, expected_message)
|
---|
208 |
|
---|
209 | def test_opt_string_empty(self):
|
---|
210 | self.assertTypeError(make_option,
|
---|
211 | "at least one option string must be supplied")
|
---|
212 |
|
---|
213 | def test_opt_string_too_short(self):
|
---|
214 | self.assertOptionError(
|
---|
215 | "invalid option string 'b': must be at least two characters long",
|
---|
216 | ["b"])
|
---|
217 |
|
---|
218 | def test_opt_string_short_invalid(self):
|
---|
219 | self.assertOptionError(
|
---|
220 | "invalid short option string '--': must be "
|
---|
221 | "of the form -x, (x any non-dash char)",
|
---|
222 | ["--"])
|
---|
223 |
|
---|
224 | def test_opt_string_long_invalid(self):
|
---|
225 | self.assertOptionError(
|
---|
226 | "invalid long option string '---': "
|
---|
227 | "must start with --, followed by non-dash",
|
---|
228 | ["---"])
|
---|
229 |
|
---|
230 | def test_attr_invalid(self):
|
---|
231 | self.assertOptionError(
|
---|
232 | "option -b: invalid keyword arguments: bar, foo",
|
---|
233 | ["-b"], {'foo': None, 'bar': None})
|
---|
234 |
|
---|
235 | def test_action_invalid(self):
|
---|
236 | self.assertOptionError(
|
---|
237 | "option -b: invalid action: 'foo'",
|
---|
238 | ["-b"], {'action': 'foo'})
|
---|
239 |
|
---|
240 | def test_type_invalid(self):
|
---|
241 | self.assertOptionError(
|
---|
242 | "option -b: invalid option type: 'foo'",
|
---|
243 | ["-b"], {'type': 'foo'})
|
---|
244 | self.assertOptionError(
|
---|
245 | "option -b: invalid option type: 'tuple'",
|
---|
246 | ["-b"], {'type': tuple})
|
---|
247 |
|
---|
248 | def test_no_type_for_action(self):
|
---|
249 | self.assertOptionError(
|
---|
250 | "option -b: must not supply a type for action 'count'",
|
---|
251 | ["-b"], {'action': 'count', 'type': 'int'})
|
---|
252 |
|
---|
253 | def test_no_choices_list(self):
|
---|
254 | self.assertOptionError(
|
---|
255 | "option -b/--bad: must supply a list of "
|
---|
256 | "choices for type 'choice'",
|
---|
257 | ["-b", "--bad"], {'type': "choice"})
|
---|
258 |
|
---|
259 | def test_bad_choices_list(self):
|
---|
260 | typename = type('').__name__
|
---|
261 | self.assertOptionError(
|
---|
262 | "option -b/--bad: choices must be a list of "
|
---|
263 | "strings ('%s' supplied)" % typename,
|
---|
264 | ["-b", "--bad"],
|
---|
265 | {'type': "choice", 'choices':"bad choices"})
|
---|
266 |
|
---|
267 | def test_no_choices_for_type(self):
|
---|
268 | self.assertOptionError(
|
---|
269 | "option -b: must not supply choices for type 'int'",
|
---|
270 | ["-b"], {'type': 'int', 'choices':"bad"})
|
---|
271 |
|
---|
272 | def test_no_const_for_action(self):
|
---|
273 | self.assertOptionError(
|
---|
274 | "option -b: 'const' must not be supplied for action 'store'",
|
---|
275 | ["-b"], {'action': 'store', 'const': 1})
|
---|
276 |
|
---|
277 | def test_no_nargs_for_action(self):
|
---|
278 | self.assertOptionError(
|
---|
279 | "option -b: 'nargs' must not be supplied for action 'count'",
|
---|
280 | ["-b"], {'action': 'count', 'nargs': 2})
|
---|
281 |
|
---|
282 | def test_callback_not_callable(self):
|
---|
283 | self.assertOptionError(
|
---|
284 | "option -b: callback not callable: 'foo'",
|
---|
285 | ["-b"], {'action': 'callback',
|
---|
286 | 'callback': 'foo'})
|
---|
287 |
|
---|
288 | def dummy(self):
|
---|
289 | pass
|
---|
290 |
|
---|
291 | def test_callback_args_no_tuple(self):
|
---|
292 | self.assertOptionError(
|
---|
293 | "option -b: callback_args, if supplied, "
|
---|
294 | "must be a tuple: not 'foo'",
|
---|
295 | ["-b"], {'action': 'callback',
|
---|
296 | 'callback': self.dummy,
|
---|
297 | 'callback_args': 'foo'})
|
---|
298 |
|
---|
299 | def test_callback_kwargs_no_dict(self):
|
---|
300 | self.assertOptionError(
|
---|
301 | "option -b: callback_kwargs, if supplied, "
|
---|
302 | "must be a dict: not 'foo'",
|
---|
303 | ["-b"], {'action': 'callback',
|
---|
304 | 'callback': self.dummy,
|
---|
305 | 'callback_kwargs': 'foo'})
|
---|
306 |
|
---|
307 | def test_no_callback_for_action(self):
|
---|
308 | self.assertOptionError(
|
---|
309 | "option -b: callback supplied ('foo') for non-callback option",
|
---|
310 | ["-b"], {'action': 'store',
|
---|
311 | 'callback': 'foo'})
|
---|
312 |
|
---|
313 | def test_no_callback_args_for_action(self):
|
---|
314 | self.assertOptionError(
|
---|
315 | "option -b: callback_args supplied for non-callback option",
|
---|
316 | ["-b"], {'action': 'store',
|
---|
317 | 'callback_args': 'foo'})
|
---|
318 |
|
---|
319 | def test_no_callback_kwargs_for_action(self):
|
---|
320 | self.assertOptionError(
|
---|
321 | "option -b: callback_kwargs supplied for non-callback option",
|
---|
322 | ["-b"], {'action': 'store',
|
---|
323 | 'callback_kwargs': 'foo'})
|
---|
324 |
|
---|
325 | class TestOptionParser(BaseTest):
|
---|
326 | def setUp(self):
|
---|
327 | self.parser = OptionParser()
|
---|
328 | self.parser.add_option("-v", "--verbose", "-n", "--noisy",
|
---|
329 | action="store_true", dest="verbose")
|
---|
330 | self.parser.add_option("-q", "--quiet", "--silent",
|
---|
331 | action="store_false", dest="verbose")
|
---|
332 |
|
---|
333 | def test_add_option_no_Option(self):
|
---|
334 | self.assertTypeError(self.parser.add_option,
|
---|
335 | "not an Option instance: None", None)
|
---|
336 |
|
---|
337 | def test_add_option_invalid_arguments(self):
|
---|
338 | self.assertTypeError(self.parser.add_option,
|
---|
339 | "invalid arguments", None, None)
|
---|
340 |
|
---|
341 | def test_get_option(self):
|
---|
342 | opt1 = self.parser.get_option("-v")
|
---|
343 | self.assertIsInstance(opt1, Option)
|
---|
344 | self.assertEqual(opt1._short_opts, ["-v", "-n"])
|
---|
345 | self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"])
|
---|
346 | self.assertEqual(opt1.action, "store_true")
|
---|
347 | self.assertEqual(opt1.dest, "verbose")
|
---|
348 |
|
---|
349 | def test_get_option_equals(self):
|
---|
350 | opt1 = self.parser.get_option("-v")
|
---|
351 | opt2 = self.parser.get_option("--verbose")
|
---|
352 | opt3 = self.parser.get_option("-n")
|
---|
353 | opt4 = self.parser.get_option("--noisy")
|
---|
354 | self.assertTrue(opt1 is opt2 is opt3 is opt4)
|
---|
355 |
|
---|
356 | def test_has_option(self):
|
---|
357 | self.assertTrue(self.parser.has_option("-v"))
|
---|
358 | self.assertTrue(self.parser.has_option("--verbose"))
|
---|
359 |
|
---|
360 | def assertTrueremoved(self):
|
---|
361 | self.assertTrue(self.parser.get_option("-v") is None)
|
---|
362 | self.assertTrue(self.parser.get_option("--verbose") is None)
|
---|
363 | self.assertTrue(self.parser.get_option("-n") is None)
|
---|
364 | self.assertTrue(self.parser.get_option("--noisy") is None)
|
---|
365 |
|
---|
366 | self.assertFalse(self.parser.has_option("-v"))
|
---|
367 | self.assertFalse(self.parser.has_option("--verbose"))
|
---|
368 | self.assertFalse(self.parser.has_option("-n"))
|
---|
369 | self.assertFalse(self.parser.has_option("--noisy"))
|
---|
370 |
|
---|
371 | self.assertTrue(self.parser.has_option("-q"))
|
---|
372 | self.assertTrue(self.parser.has_option("--silent"))
|
---|
373 |
|
---|
374 | def test_remove_short_opt(self):
|
---|
375 | self.parser.remove_option("-n")
|
---|
376 | self.assertTrueremoved()
|
---|
377 |
|
---|
378 | def test_remove_long_opt(self):
|
---|
379 | self.parser.remove_option("--verbose")
|
---|
380 | self.assertTrueremoved()
|
---|
381 |
|
---|
382 | def test_remove_nonexistent(self):
|
---|
383 | self.assertRaises(self.parser.remove_option, ('foo',), None,
|
---|
384 | ValueError, "no such option 'foo'")
|
---|
385 |
|
---|
386 | def test_refleak(self):
|
---|
387 | # If an OptionParser is carrying around a reference to a large
|
---|
388 | # object, various cycles can prevent it from being GC'd in
|
---|
389 | # a timely fashion. destroy() breaks the cycles to ensure stuff
|
---|
390 | # can be cleaned up.
|
---|
391 | big_thing = [42]
|
---|
392 | refcount = sys.getrefcount(big_thing)
|
---|
393 | parser = OptionParser()
|
---|
394 | parser.add_option("-a", "--aaarggh")
|
---|
395 | parser.big_thing = big_thing
|
---|
396 |
|
---|
397 | parser.destroy()
|
---|
398 | #self.assertEqual(refcount, sys.getrefcount(big_thing))
|
---|
399 | del parser
|
---|
400 | self.assertEqual(refcount, sys.getrefcount(big_thing))
|
---|
401 |
|
---|
402 |
|
---|
403 | class TestOptionValues(BaseTest):
|
---|
404 | def setUp(self):
|
---|
405 | pass
|
---|
406 |
|
---|
407 | def test_basics(self):
|
---|
408 | values = Values()
|
---|
409 | self.assertEqual(vars(values), {})
|
---|
410 | self.assertEqual(values, {})
|
---|
411 | self.assertNotEqual(values, {"foo": "bar"})
|
---|
412 | self.assertNotEqual(values, "")
|
---|
413 |
|
---|
414 | dict = {"foo": "bar", "baz": 42}
|
---|
415 | values = Values(defaults=dict)
|
---|
416 | self.assertEqual(vars(values), dict)
|
---|
417 | self.assertEqual(values, dict)
|
---|
418 | self.assertNotEqual(values, {"foo": "bar"})
|
---|
419 | self.assertNotEqual(values, {})
|
---|
420 | self.assertNotEqual(values, "")
|
---|
421 | self.assertNotEqual(values, [])
|
---|
422 |
|
---|
423 |
|
---|
424 | class TestTypeAliases(BaseTest):
|
---|
425 | def setUp(self):
|
---|
426 | self.parser = OptionParser()
|
---|
427 |
|
---|
428 | def test_str_aliases_string(self):
|
---|
429 | self.parser.add_option("-s", type="str")
|
---|
430 | self.assertEqual(self.parser.get_option("-s").type, "string")
|
---|
431 |
|
---|
432 | def test_new_type_object(self):
|
---|
433 | self.parser.add_option("-s", type=str)
|
---|
434 | self.assertEqual(self.parser.get_option("-s").type, "string")
|
---|
435 | self.parser.add_option("-x", type=int)
|
---|
436 | self.assertEqual(self.parser.get_option("-x").type, "int")
|
---|
437 |
|
---|
438 | def test_old_type_object(self):
|
---|
439 | self.parser.add_option("-s", type=types.StringType)
|
---|
440 | self.assertEqual(self.parser.get_option("-s").type, "string")
|
---|
441 | self.parser.add_option("-x", type=types.IntType)
|
---|
442 | self.assertEqual(self.parser.get_option("-x").type, "int")
|
---|
443 |
|
---|
444 |
|
---|
445 | # Custom type for testing processing of default values.
|
---|
446 | _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 }
|
---|
447 |
|
---|
448 | def _check_duration(option, opt, value):
|
---|
449 | try:
|
---|
450 | if value[-1].isdigit():
|
---|
451 | return int(value)
|
---|
452 | else:
|
---|
453 | return int(value[:-1]) * _time_units[value[-1]]
|
---|
454 | except (ValueError, IndexError):
|
---|
455 | raise OptionValueError(
|
---|
456 | 'option %s: invalid duration: %r' % (opt, value))
|
---|
457 |
|
---|
458 | class DurationOption(Option):
|
---|
459 | TYPES = Option.TYPES + ('duration',)
|
---|
460 | TYPE_CHECKER = copy.copy(Option.TYPE_CHECKER)
|
---|
461 | TYPE_CHECKER['duration'] = _check_duration
|
---|
462 |
|
---|
463 | class TestDefaultValues(BaseTest):
|
---|
464 | def setUp(self):
|
---|
465 | self.parser = OptionParser()
|
---|
466 | self.parser.add_option("-v", "--verbose", default=True)
|
---|
467 | self.parser.add_option("-q", "--quiet", dest='verbose')
|
---|
468 | self.parser.add_option("-n", type="int", default=37)
|
---|
469 | self.parser.add_option("-m", type="int")
|
---|
470 | self.parser.add_option("-s", default="foo")
|
---|
471 | self.parser.add_option("-t")
|
---|
472 | self.parser.add_option("-u", default=None)
|
---|
473 | self.expected = { 'verbose': True,
|
---|
474 | 'n': 37,
|
---|
475 | 'm': None,
|
---|
476 | 's': "foo",
|
---|
477 | 't': None,
|
---|
478 | 'u': None }
|
---|
479 |
|
---|
480 | def test_basic_defaults(self):
|
---|
481 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
482 |
|
---|
483 | def test_mixed_defaults_post(self):
|
---|
484 | self.parser.set_defaults(n=42, m=-100)
|
---|
485 | self.expected.update({'n': 42, 'm': -100})
|
---|
486 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
487 |
|
---|
488 | def test_mixed_defaults_pre(self):
|
---|
489 | self.parser.set_defaults(x="barf", y="blah")
|
---|
490 | self.parser.add_option("-x", default="frob")
|
---|
491 | self.parser.add_option("-y")
|
---|
492 |
|
---|
493 | self.expected.update({'x': "frob", 'y': "blah"})
|
---|
494 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
495 |
|
---|
496 | self.parser.remove_option("-y")
|
---|
497 | self.parser.add_option("-y", default=None)
|
---|
498 | self.expected.update({'y': None})
|
---|
499 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
500 |
|
---|
501 | def test_process_default(self):
|
---|
502 | self.parser.option_class = DurationOption
|
---|
503 | self.parser.add_option("-d", type="duration", default=300)
|
---|
504 | self.parser.add_option("-e", type="duration", default="6m")
|
---|
505 | self.parser.set_defaults(n="42")
|
---|
506 | self.expected.update({'d': 300, 'e': 360, 'n': 42})
|
---|
507 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
508 |
|
---|
509 | self.parser.set_process_default_values(False)
|
---|
510 | self.expected.update({'d': 300, 'e': "6m", 'n': "42"})
|
---|
511 | self.assertEqual(self.parser.get_default_values(), self.expected)
|
---|
512 |
|
---|
513 |
|
---|
514 | class TestProgName(BaseTest):
|
---|
515 | """
|
---|
516 | Test that %prog expands to the right thing in usage, version,
|
---|
517 | and help strings.
|
---|
518 | """
|
---|
519 |
|
---|
520 | def assertUsage(self, parser, expected_usage):
|
---|
521 | self.assertEqual(parser.get_usage(), expected_usage)
|
---|
522 |
|
---|
523 | def assertVersion(self, parser, expected_version):
|
---|
524 | self.assertEqual(parser.get_version(), expected_version)
|
---|
525 |
|
---|
526 |
|
---|
527 | def test_default_progname(self):
|
---|
528 | # Make sure that program name taken from sys.argv[0] by default.
|
---|
529 | save_argv = sys.argv[:]
|
---|
530 | try:
|
---|
531 | sys.argv[0] = os.path.join("foo", "bar", "baz.py")
|
---|
532 | parser = OptionParser("%prog ...", version="%prog 1.2")
|
---|
533 | expected_usage = "Usage: baz.py ...\n"
|
---|
534 | self.assertUsage(parser, expected_usage)
|
---|
535 | self.assertVersion(parser, "baz.py 1.2")
|
---|
536 | self.assertHelp(parser,
|
---|
537 | expected_usage + "\n" +
|
---|
538 | "Options:\n"
|
---|
539 | " --version show program's version number and exit\n"
|
---|
540 | " -h, --help show this help message and exit\n")
|
---|
541 | finally:
|
---|
542 | sys.argv[:] = save_argv
|
---|
543 |
|
---|
544 | def test_custom_progname(self):
|
---|
545 | parser = OptionParser(prog="thingy",
|
---|
546 | version="%prog 0.1",
|
---|
547 | usage="%prog arg arg")
|
---|
548 | parser.remove_option("-h")
|
---|
549 | parser.remove_option("--version")
|
---|
550 | expected_usage = "Usage: thingy arg arg\n"
|
---|
551 | self.assertUsage(parser, expected_usage)
|
---|
552 | self.assertVersion(parser, "thingy 0.1")
|
---|
553 | self.assertHelp(parser, expected_usage + "\n")
|
---|
554 |
|
---|
555 |
|
---|
556 | class TestExpandDefaults(BaseTest):
|
---|
557 | def setUp(self):
|
---|
558 | self.parser = OptionParser(prog="test")
|
---|
559 | self.help_prefix = """\
|
---|
560 | Usage: test [options]
|
---|
561 |
|
---|
562 | Options:
|
---|
563 | -h, --help show this help message and exit
|
---|
564 | """
|
---|
565 | self.file_help = "read from FILE [default: %default]"
|
---|
566 | self.expected_help_file = self.help_prefix + \
|
---|
567 | " -f FILE, --file=FILE read from FILE [default: foo.txt]\n"
|
---|
568 | self.expected_help_none = self.help_prefix + \
|
---|
569 | " -f FILE, --file=FILE read from FILE [default: none]\n"
|
---|
570 |
|
---|
571 | def test_option_default(self):
|
---|
572 | self.parser.add_option("-f", "--file",
|
---|
573 | default="foo.txt",
|
---|
574 | help=self.file_help)
|
---|
575 | self.assertHelp(self.parser, self.expected_help_file)
|
---|
576 |
|
---|
577 | def test_parser_default_1(self):
|
---|
578 | self.parser.add_option("-f", "--file",
|
---|
579 | help=self.file_help)
|
---|
580 | self.parser.set_default('file', "foo.txt")
|
---|
581 | self.assertHelp(self.parser, self.expected_help_file)
|
---|
582 |
|
---|
583 | def test_parser_default_2(self):
|
---|
584 | self.parser.add_option("-f", "--file",
|
---|
585 | help=self.file_help)
|
---|
586 | self.parser.set_defaults(file="foo.txt")
|
---|
587 | self.assertHelp(self.parser, self.expected_help_file)
|
---|
588 |
|
---|
589 | def test_no_default(self):
|
---|
590 | self.parser.add_option("-f", "--file",
|
---|
591 | help=self.file_help)
|
---|
592 | self.assertHelp(self.parser, self.expected_help_none)
|
---|
593 |
|
---|
594 | def test_default_none_1(self):
|
---|
595 | self.parser.add_option("-f", "--file",
|
---|
596 | default=None,
|
---|
597 | help=self.file_help)
|
---|
598 | self.assertHelp(self.parser, self.expected_help_none)
|
---|
599 |
|
---|
600 | def test_default_none_2(self):
|
---|
601 | self.parser.add_option("-f", "--file",
|
---|
602 | help=self.file_help)
|
---|
603 | self.parser.set_defaults(file=None)
|
---|
604 | self.assertHelp(self.parser, self.expected_help_none)
|
---|
605 |
|
---|
606 | def test_float_default(self):
|
---|
607 | self.parser.add_option(
|
---|
608 | "-p", "--prob",
|
---|
609 | help="blow up with probability PROB [default: %default]")
|
---|
610 | self.parser.set_defaults(prob=0.43)
|
---|
611 | expected_help = self.help_prefix + \
|
---|
612 | " -p PROB, --prob=PROB blow up with probability PROB [default: 0.43]\n"
|
---|
613 | self.assertHelp(self.parser, expected_help)
|
---|
614 |
|
---|
615 | def test_alt_expand(self):
|
---|
616 | self.parser.add_option("-f", "--file",
|
---|
617 | default="foo.txt",
|
---|
618 | help="read from FILE [default: *DEFAULT*]")
|
---|
619 | self.parser.formatter.default_tag = "*DEFAULT*"
|
---|
620 | self.assertHelp(self.parser, self.expected_help_file)
|
---|
621 |
|
---|
622 | def test_no_expand(self):
|
---|
623 | self.parser.add_option("-f", "--file",
|
---|
624 | default="foo.txt",
|
---|
625 | help="read from %default file")
|
---|
626 | self.parser.formatter.default_tag = None
|
---|
627 | expected_help = self.help_prefix + \
|
---|
628 | " -f FILE, --file=FILE read from %default file\n"
|
---|
629 | self.assertHelp(self.parser, expected_help)
|
---|
630 |
|
---|
631 |
|
---|
632 | # -- Test parser.parse_args() ------------------------------------------
|
---|
633 |
|
---|
634 | class TestStandard(BaseTest):
|
---|
635 | def setUp(self):
|
---|
636 | options = [make_option("-a", type="string"),
|
---|
637 | make_option("-b", "--boo", type="int", dest='boo'),
|
---|
638 | make_option("--foo", action="append")]
|
---|
639 |
|
---|
640 | self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
|
---|
641 | option_list=options)
|
---|
642 |
|
---|
643 | def test_required_value(self):
|
---|
644 | self.assertParseFail(["-a"], "-a option requires an argument")
|
---|
645 |
|
---|
646 | def test_invalid_integer(self):
|
---|
647 | self.assertParseFail(["-b", "5x"],
|
---|
648 | "option -b: invalid integer value: '5x'")
|
---|
649 |
|
---|
650 | def test_no_such_option(self):
|
---|
651 | self.assertParseFail(["--boo13"], "no such option: --boo13")
|
---|
652 |
|
---|
653 | def test_long_invalid_integer(self):
|
---|
654 | self.assertParseFail(["--boo=x5"],
|
---|
655 | "option --boo: invalid integer value: 'x5'")
|
---|
656 |
|
---|
657 | def test_empty(self):
|
---|
658 | self.assertParseOK([], {'a': None, 'boo': None, 'foo': None}, [])
|
---|
659 |
|
---|
660 | def test_shortopt_empty_longopt_append(self):
|
---|
661 | self.assertParseOK(["-a", "", "--foo=blah", "--foo="],
|
---|
662 | {'a': "", 'boo': None, 'foo': ["blah", ""]},
|
---|
663 | [])
|
---|
664 |
|
---|
665 | def test_long_option_append(self):
|
---|
666 | self.assertParseOK(["--foo", "bar", "--foo", "", "--foo=x"],
|
---|
667 | {'a': None,
|
---|
668 | 'boo': None,
|
---|
669 | 'foo': ["bar", "", "x"]},
|
---|
670 | [])
|
---|
671 |
|
---|
672 | def test_option_argument_joined(self):
|
---|
673 | self.assertParseOK(["-abc"],
|
---|
674 | {'a': "bc", 'boo': None, 'foo': None},
|
---|
675 | [])
|
---|
676 |
|
---|
677 | def test_option_argument_split(self):
|
---|
678 | self.assertParseOK(["-a", "34"],
|
---|
679 | {'a': "34", 'boo': None, 'foo': None},
|
---|
680 | [])
|
---|
681 |
|
---|
682 | def test_option_argument_joined_integer(self):
|
---|
683 | self.assertParseOK(["-b34"],
|
---|
684 | {'a': None, 'boo': 34, 'foo': None},
|
---|
685 | [])
|
---|
686 |
|
---|
687 | def test_option_argument_split_negative_integer(self):
|
---|
688 | self.assertParseOK(["-b", "-5"],
|
---|
689 | {'a': None, 'boo': -5, 'foo': None},
|
---|
690 | [])
|
---|
691 |
|
---|
692 | def test_long_option_argument_joined(self):
|
---|
693 | self.assertParseOK(["--boo=13"],
|
---|
694 | {'a': None, 'boo': 13, 'foo': None},
|
---|
695 | [])
|
---|
696 |
|
---|
697 | def test_long_option_argument_split(self):
|
---|
698 | self.assertParseOK(["--boo", "111"],
|
---|
699 | {'a': None, 'boo': 111, 'foo': None},
|
---|
700 | [])
|
---|
701 |
|
---|
702 | def test_long_option_short_option(self):
|
---|
703 | self.assertParseOK(["--foo=bar", "-axyz"],
|
---|
704 | {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
|
---|
705 | [])
|
---|
706 |
|
---|
707 | def test_abbrev_long_option(self):
|
---|
708 | self.assertParseOK(["--f=bar", "-axyz"],
|
---|
709 | {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
|
---|
710 | [])
|
---|
711 |
|
---|
712 | def test_defaults(self):
|
---|
713 | (options, args) = self.parser.parse_args([])
|
---|
714 | defaults = self.parser.get_default_values()
|
---|
715 | self.assertEqual(vars(defaults), vars(options))
|
---|
716 |
|
---|
717 | def test_ambiguous_option(self):
|
---|
718 | self.parser.add_option("--foz", action="store",
|
---|
719 | type="string", dest="foo")
|
---|
720 | self.assertParseFail(["--f=bar"],
|
---|
721 | "ambiguous option: --f (--foo, --foz?)")
|
---|
722 |
|
---|
723 |
|
---|
724 | def test_short_and_long_option_split(self):
|
---|
725 | self.assertParseOK(["-a", "xyz", "--foo", "bar"],
|
---|
726 | {'a': 'xyz', 'boo': None, 'foo': ["bar"]},
|
---|
727 | []),
|
---|
728 |
|
---|
729 | def test_short_option_split_long_option_append(self):
|
---|
730 | self.assertParseOK(["--foo=bar", "-b", "123", "--foo", "baz"],
|
---|
731 | {'a': None, 'boo': 123, 'foo': ["bar", "baz"]},
|
---|
732 | [])
|
---|
733 |
|
---|
734 | def test_short_option_split_one_positional_arg(self):
|
---|
735 | self.assertParseOK(["-a", "foo", "bar"],
|
---|
736 | {'a': "foo", 'boo': None, 'foo': None},
|
---|
737 | ["bar"]),
|
---|
738 |
|
---|
739 | def test_short_option_consumes_separator(self):
|
---|
740 | self.assertParseOK(["-a", "--", "foo", "bar"],
|
---|
741 | {'a': "--", 'boo': None, 'foo': None},
|
---|
742 | ["foo", "bar"]),
|
---|
743 | self.assertParseOK(["-a", "--", "--foo", "bar"],
|
---|
744 | {'a': "--", 'boo': None, 'foo': ["bar"]},
|
---|
745 | []),
|
---|
746 |
|
---|
747 | def test_short_option_joined_and_separator(self):
|
---|
748 | self.assertParseOK(["-ab", "--", "--foo", "bar"],
|
---|
749 | {'a': "b", 'boo': None, 'foo': None},
|
---|
750 | ["--foo", "bar"]),
|
---|
751 |
|
---|
752 | def test_hyphen_becomes_positional_arg(self):
|
---|
753 | self.assertParseOK(["-ab", "-", "--foo", "bar"],
|
---|
754 | {'a': "b", 'boo': None, 'foo': ["bar"]},
|
---|
755 | ["-"])
|
---|
756 |
|
---|
757 | def test_no_append_versus_append(self):
|
---|
758 | self.assertParseOK(["-b3", "-b", "5", "--foo=bar", "--foo", "baz"],
|
---|
759 | {'a': None, 'boo': 5, 'foo': ["bar", "baz"]},
|
---|
760 | [])
|
---|
761 |
|
---|
762 | def test_option_consumes_optionlike_string(self):
|
---|
763 | self.assertParseOK(["-a", "-b3"],
|
---|
764 | {'a': "-b3", 'boo': None, 'foo': None},
|
---|
765 | [])
|
---|
766 |
|
---|
767 | def test_combined_single_invalid_option(self):
|
---|
768 | self.parser.add_option("-t", action="store_true")
|
---|
769 | self.assertParseFail(["-test"],
|
---|
770 | "no such option: -e")
|
---|
771 |
|
---|
772 | def test_add_option_accepts_unicode(self):
|
---|
773 | self.parser.add_option(u"-u", u"--unicode", action="store_true")
|
---|
774 | self.assertParseOK(["-u"],
|
---|
775 | {'a': None, 'boo': None, 'foo': None, 'unicode': True},
|
---|
776 | [])
|
---|
777 |
|
---|
778 |
|
---|
779 | class 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 |
|
---|
814 | class 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 |
|
---|
837 | class 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 |
|
---|
895 | class 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 |
|
---|
920 | class 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 |
|
---|
949 | class 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 |
|
---|
967 | class 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 |
|
---|
983 | class 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 |
|
---|
1017 | class 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(test_support.TESTFN):
|
---|
1026 | os.rmdir(test_support.TESTFN)
|
---|
1027 | elif os.path.isfile(test_support.TESTFN):
|
---|
1028 | os.unlink(test_support.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 | open(test_support.TESTFN, "w").close()
|
---|
1044 | self.assertParseOK(["--file", test_support.TESTFN, "-afoo"],
|
---|
1045 | {'file': test_support.TESTFN, 'a': 'foo'},
|
---|
1046 | [])
|
---|
1047 |
|
---|
1048 | def test_filetype_noexist(self):
|
---|
1049 | self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
|
---|
1050 | "%s: file does not exist" %
|
---|
1051 | test_support.TESTFN)
|
---|
1052 |
|
---|
1053 | def test_filetype_notfile(self):
|
---|
1054 | os.mkdir(test_support.TESTFN)
|
---|
1055 | self.assertParseFail(["--file", test_support.TESTFN, "-afoo"],
|
---|
1056 | "%s: not a regular file" %
|
---|
1057 | test_support.TESTFN)
|
---|
1058 |
|
---|
1059 |
|
---|
1060 | class 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 |
|
---|
1091 | class 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 |
|
---|
1145 | class 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 |
|
---|
1170 | class 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 |
|
---|
1199 | class 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 |
|
---|
1224 | class 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 |
|
---|
1236 | class 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 |
|
---|
1289 | class 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 |
|
---|
1299 | class 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 |
|
---|
1325 | class 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"], """\
|
---|
1347 | Options:
|
---|
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 |
|
---|
1368 | class 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"], """\
|
---|
1386 | Options:
|
---|
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 = """\
|
---|
1399 | Usage: bar.py [options]
|
---|
1400 |
|
---|
1401 | Options:
|
---|
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 = """\
|
---|
1410 | Usage: bar.py [options]
|
---|
1411 |
|
---|
1412 | Options:
|
---|
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 = """\
|
---|
1421 | Usage
|
---|
1422 | =====
|
---|
1423 | bar.py [options]
|
---|
1424 |
|
---|
1425 | Options
|
---|
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 = """\
|
---|
1435 | Usage: bar.py [options]
|
---|
1436 |
|
---|
1437 | Options:
|
---|
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 | class TestHelp(BaseTest):
|
---|
1448 | def setUp(self):
|
---|
1449 | self.parser = self.make_parser(80)
|
---|
1450 |
|
---|
1451 | def make_parser(self, columns):
|
---|
1452 | options = [
|
---|
1453 | make_option("-a", type="string", dest='a',
|
---|
1454 | metavar="APPLE", help="throw APPLEs at basket"),
|
---|
1455 | make_option("-b", "--boo", type="int", dest='boo',
|
---|
1456 | metavar="NUM",
|
---|
1457 | help=
|
---|
1458 | "shout \"boo!\" NUM times (in order to frighten away "
|
---|
1459 | "all the evil spirits that cause trouble and mayhem)"),
|
---|
1460 | make_option("--foo", action="append", type="string", dest='foo',
|
---|
1461 | help="store FOO in the foo list for later fooing"),
|
---|
1462 | ]
|
---|
1463 |
|
---|
1464 | # We need to set COLUMNS for the OptionParser constructor, but
|
---|
1465 | # we must restore its original value -- otherwise, this test
|
---|
1466 | # screws things up for other tests when it's part of the Python
|
---|
1467 | # test suite.
|
---|
1468 | with test_support.EnvironmentVarGuard() as env:
|
---|
1469 | env['COLUMNS'] = str(columns)
|
---|
1470 | return InterceptingOptionParser(option_list=options)
|
---|
1471 |
|
---|
1472 | def assertHelpEquals(self, expected_output):
|
---|
1473 | if type(expected_output) is types.UnicodeType:
|
---|
1474 | encoding = self.parser._get_encoding(sys.stdout)
|
---|
1475 | expected_output = expected_output.encode(encoding, "replace")
|
---|
1476 |
|
---|
1477 | save_argv = sys.argv[:]
|
---|
1478 | try:
|
---|
1479 | # Make optparse believe bar.py is being executed.
|
---|
1480 | sys.argv[0] = os.path.join("foo", "bar.py")
|
---|
1481 | self.assertOutput(["-h"], expected_output)
|
---|
1482 | finally:
|
---|
1483 | sys.argv[:] = save_argv
|
---|
1484 |
|
---|
1485 | def test_help(self):
|
---|
1486 | self.assertHelpEquals(_expected_help_basic)
|
---|
1487 |
|
---|
1488 | def test_help_old_usage(self):
|
---|
1489 | self.parser.set_usage("Usage: %prog [options]")
|
---|
1490 | self.assertHelpEquals(_expected_help_basic)
|
---|
1491 |
|
---|
1492 | def test_help_long_opts_first(self):
|
---|
1493 | self.parser.formatter.short_first = 0
|
---|
1494 | self.assertHelpEquals(_expected_help_long_opts_first)
|
---|
1495 |
|
---|
1496 | def test_help_title_formatter(self):
|
---|
1497 | with test_support.EnvironmentVarGuard() as env:
|
---|
1498 | env["COLUMNS"] = "80"
|
---|
1499 | self.parser.formatter = TitledHelpFormatter()
|
---|
1500 | self.assertHelpEquals(_expected_help_title_formatter)
|
---|
1501 |
|
---|
1502 | def test_wrap_columns(self):
|
---|
1503 | # Ensure that wrapping respects $COLUMNS environment variable.
|
---|
1504 | # Need to reconstruct the parser, since that's the only time
|
---|
1505 | # we look at $COLUMNS.
|
---|
1506 | self.parser = self.make_parser(60)
|
---|
1507 | self.assertHelpEquals(_expected_help_short_lines)
|
---|
1508 |
|
---|
1509 | def test_help_unicode(self):
|
---|
1510 | self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE)
|
---|
1511 | self.parser.add_option("-a", action="store_true", help=u"ol\u00E9!")
|
---|
1512 | expect = u"""\
|
---|
1513 | Options:
|
---|
1514 | -h, --help show this help message and exit
|
---|
1515 | -a ol\u00E9!
|
---|
1516 | """
|
---|
1517 | self.assertHelpEquals(expect)
|
---|
1518 |
|
---|
1519 | def test_help_unicode_description(self):
|
---|
1520 | self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE,
|
---|
1521 | description=u"ol\u00E9!")
|
---|
1522 | expect = u"""\
|
---|
1523 | ol\u00E9!
|
---|
1524 |
|
---|
1525 | Options:
|
---|
1526 | -h, --help show this help message and exit
|
---|
1527 | """
|
---|
1528 | self.assertHelpEquals(expect)
|
---|
1529 |
|
---|
1530 | def test_help_description_groups(self):
|
---|
1531 | self.parser.set_description(
|
---|
1532 | "This is the program description for %prog. %prog has "
|
---|
1533 | "an option group as well as single options.")
|
---|
1534 |
|
---|
1535 | group = OptionGroup(
|
---|
1536 | self.parser, "Dangerous Options",
|
---|
1537 | "Caution: use of these options is at your own risk. "
|
---|
1538 | "It is believed that some of them bite.")
|
---|
1539 | group.add_option("-g", action="store_true", help="Group option.")
|
---|
1540 | self.parser.add_option_group(group)
|
---|
1541 |
|
---|
1542 | expect = """\
|
---|
1543 | Usage: bar.py [options]
|
---|
1544 |
|
---|
1545 | This is the program description for bar.py. bar.py has an option group as
|
---|
1546 | well as single options.
|
---|
1547 |
|
---|
1548 | Options:
|
---|
1549 | -a APPLE throw APPLEs at basket
|
---|
1550 | -b NUM, --boo=NUM shout "boo!" NUM times (in order to frighten away all the
|
---|
1551 | evil spirits that cause trouble and mayhem)
|
---|
1552 | --foo=FOO store FOO in the foo list for later fooing
|
---|
1553 | -h, --help show this help message and exit
|
---|
1554 |
|
---|
1555 | Dangerous Options:
|
---|
1556 | Caution: use of these options is at your own risk. It is believed
|
---|
1557 | that some of them bite.
|
---|
1558 |
|
---|
1559 | -g Group option.
|
---|
1560 | """
|
---|
1561 |
|
---|
1562 | self.assertHelpEquals(expect)
|
---|
1563 |
|
---|
1564 | self.parser.epilog = "Please report bugs to /dev/null."
|
---|
1565 | self.assertHelpEquals(expect + "\nPlease report bugs to /dev/null.\n")
|
---|
1566 |
|
---|
1567 |
|
---|
1568 | class TestMatchAbbrev(BaseTest):
|
---|
1569 | def test_match_abbrev(self):
|
---|
1570 | self.assertEqual(_match_abbrev("--f",
|
---|
1571 | {"--foz": None,
|
---|
1572 | "--foo": None,
|
---|
1573 | "--fie": None,
|
---|
1574 | "--f": None}),
|
---|
1575 | "--f")
|
---|
1576 |
|
---|
1577 | def test_match_abbrev_error(self):
|
---|
1578 | s = "--f"
|
---|
1579 | wordmap = {"--foz": None, "--foo": None, "--fie": None}
|
---|
1580 | self.assertRaises(
|
---|
1581 | _match_abbrev, (s, wordmap), None,
|
---|
1582 | BadOptionError, "ambiguous option: --f (--fie, --foo, --foz?)")
|
---|
1583 |
|
---|
1584 |
|
---|
1585 | class TestParseNumber(BaseTest):
|
---|
1586 | def setUp(self):
|
---|
1587 | self.parser = InterceptingOptionParser()
|
---|
1588 | self.parser.add_option("-n", type=int)
|
---|
1589 | self.parser.add_option("-l", type=long)
|
---|
1590 |
|
---|
1591 | def test_parse_num_fail(self):
|
---|
1592 | self.assertRaises(
|
---|
1593 | _parse_num, ("", int), {},
|
---|
1594 | ValueError,
|
---|
1595 | re.compile(r"invalid literal for int().*: '?'?"))
|
---|
1596 | self.assertRaises(
|
---|
1597 | _parse_num, ("0xOoops", long), {},
|
---|
1598 | ValueError,
|
---|
1599 | re.compile(r"invalid literal for long().*: '?0xOoops'?"))
|
---|
1600 |
|
---|
1601 | def test_parse_num_ok(self):
|
---|
1602 | self.assertEqual(_parse_num("0", int), 0)
|
---|
1603 | self.assertEqual(_parse_num("0x10", int), 16)
|
---|
1604 | self.assertEqual(_parse_num("0XA", long), 10L)
|
---|
1605 | self.assertEqual(_parse_num("010", long), 8L)
|
---|
1606 | self.assertEqual(_parse_num("0b11", int), 3)
|
---|
1607 | self.assertEqual(_parse_num("0b", long), 0L)
|
---|
1608 |
|
---|
1609 | def test_numeric_options(self):
|
---|
1610 | self.assertParseOK(["-n", "42", "-l", "0x20"],
|
---|
1611 | { "n": 42, "l": 0x20 }, [])
|
---|
1612 | self.assertParseOK(["-n", "0b0101", "-l010"],
|
---|
1613 | { "n": 5, "l": 8 }, [])
|
---|
1614 | self.assertParseFail(["-n008"],
|
---|
1615 | "option -n: invalid integer value: '008'")
|
---|
1616 | self.assertParseFail(["-l0b0123"],
|
---|
1617 | "option -l: invalid long integer value: '0b0123'")
|
---|
1618 | self.assertParseFail(["-l", "0x12x"],
|
---|
1619 | "option -l: invalid long integer value: '0x12x'")
|
---|
1620 |
|
---|
1621 |
|
---|
1622 | def test_main():
|
---|
1623 | test_support.run_unittest(__name__)
|
---|
1624 |
|
---|
1625 | if __name__ == '__main__':
|
---|
1626 | test_main()
|
---|