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