Prepare for python 3.0: minimize "types" module where possible (gbrandl).
[docutils.git] / test / DocutilsTestSupport.py
blob7d286b283eed0a1ab2b43f9c3540c2d4b8d1c274
1 # $Id$
2 # Authors: David Goodger <goodger@python.org>;
3 # Garth Kidd <garth@deadlybloodyserious.com>
4 # Copyright: This module has been placed in the public domain.
6 """
7 Exports the following:
9 :Modules:
10 - `statemachine` is 'docutils.statemachine'
11 - `nodes` is 'docutils.nodes'
12 - `urischemes` is 'docutils.urischemes'
13 - `utils` is 'docutils.utils'
14 - `transforms` is 'docutils.transforms'
15 - `states` is 'docutils.parsers.rst.states'
16 - `tableparser` is 'docutils.parsers.rst.tableparser'
18 :Classes:
19 - `StandardTestCase`
20 - `CustomTestCase`
21 - `CustomTestSuite`
22 - `TransformTestCase`
23 - `TransformTestSuite`
24 - `ParserTestCase`
25 - `ParserTestSuite`
26 - `ParserTransformTestCase`
27 - `PEPParserTestCase`
28 - `PEPParserTestSuite`
29 - `GridTableParserTestCase`
30 - `GridTableParserTestSuite`
31 - `SimpleTableParserTestCase`
32 - `SimpleTableParserTestSuite`
33 - `WriterPublishTestCase`
34 - `LatexWriterPublishTestCase`
35 - `PseudoXMLWriterPublishTestCase`
36 - `HtmlWriterPublishTestCase`
37 - `PublishTestSuite`
38 - `HtmlFragmentTestSuite`
39 - `DevNull` (output sink)
40 """
41 __docformat__ = 'reStructuredText'
43 import sys
44 import os
45 import unittest
46 import re
47 import inspect
48 import traceback
49 from pprint import pformat
51 testroot = os.path.abspath(os.path.dirname(__file__) or os.curdir)
52 os.chdir(testroot)
53 sys.path.insert(0, os.path.normpath(os.path.join(testroot, '..')))
54 sys.path.insert(0, testroot)
55 sys.path.append(os.path.normpath(os.path.join(testroot, '..', 'extras')))
57 try:
58 import docutils_difflib
59 import package_unittest
60 import docutils
61 import docutils.core
62 from docutils import frontend, nodes, statemachine, urischemes, utils
63 from docutils.transforms import universal
64 from docutils.parsers import rst
65 from docutils.parsers.rst import states, tableparser, roles, languages
66 from docutils.readers import standalone, pep
67 from docutils.readers.python import moduleparser
68 from docutils.statemachine import StringList, string2lines
69 except ImportError:
70 # The importing module (usually __init__.py in one of the
71 # subdirectories) may catch ImportErrors in order to detect the
72 # absence of DocutilsTestSupport in sys.path. Thus, ImportErrors
73 # resulting from problems with importing Docutils modules must
74 # caught here.
75 traceback.print_exc()
76 sys.exit(1)
79 try:
80 import mypdb as pdb
81 except:
82 import pdb
85 # Hack to make repr(StringList) look like repr(list):
86 StringList.__repr__ = StringList.__str__
89 class DevNull:
91 """Output sink."""
93 def write(self, string):
94 pass
96 def close(self):
97 pass
100 class StandardTestCase(unittest.TestCase):
103 Helper class, providing the same interface as unittest.TestCase,
104 but with useful setUp and comparison methods.
107 def setUp(self):
108 os.chdir(testroot)
110 def failUnlessEqual(self, first, second, msg=None):
111 """Fail if the two objects are unequal as determined by the '=='
112 operator.
114 if not first == second:
115 raise self.failureException, \
116 (msg or '%s != %s' % _format_str(first, second))
118 def failIfEqual(self, first, second, msg=None):
119 """Fail if the two objects are equal as determined by the '=='
120 operator.
122 if first == second:
123 raise self.failureException, \
124 (msg or '%s == %s' % _format_str(first, second))
126 # Synonyms for assertion methods
128 assertEqual = assertEquals = failUnlessEqual
130 assertNotEqual = assertNotEquals = failIfEqual
133 class CustomTestCase(StandardTestCase):
136 Helper class, providing extended functionality over unittest.TestCase.
138 The methods failUnlessEqual and failIfEqual have been overwritten
139 to provide better support for multi-line strings. Furthermore,
140 see the compare_output method and the parameter list of __init__.
143 compare = docutils_difflib.Differ().compare
144 """Comparison method shared by all subclasses."""
146 def __init__(self, method_name, input, expected, id, run_in_debugger=0,
147 suite_settings=None):
149 Initialise the CustomTestCase.
151 Arguments:
153 method_name -- name of test method to run.
154 input -- input to the parser.
155 expected -- expected output from the parser.
156 id -- unique test identifier, used by the test framework.
157 run_in_debugger -- if true, run this test under the pdb debugger.
158 suite_settings -- settings overrides for this test suite.
160 self.id = id
161 self.input = input
162 self.expected = expected
163 self.run_in_debugger = run_in_debugger
164 self.suite_settings = suite_settings.copy() or {}
166 # Ring your mother.
167 unittest.TestCase.__init__(self, method_name)
169 def __str__(self):
171 Return string conversion. Overridden to give test id, in addition to
172 method name.
174 return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
176 def __repr__(self):
177 return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
179 def clear_roles(self):
180 # Language-specific roles and roles added by the
181 # "default-role" and "role" directives are currently stored
182 # globally in the roles._roles dictionary. This workaround
183 # empties that dictionary.
184 roles._roles = {}
186 def setUp(self):
187 StandardTestCase.setUp(self)
188 self.clear_roles()
190 def compare_output(self, input, output, expected):
191 """`input`, `output`, and `expected` should all be strings."""
192 if isinstance(input, unicode):
193 input = input.encode('raw_unicode_escape')
194 if isinstance(output, unicode):
195 output = output.encode('raw_unicode_escape')
196 if isinstance(expected, unicode):
197 expected = expected.encode('raw_unicode_escape')
198 try:
199 self.assertEquals(output, expected)
200 except AssertionError, error:
201 print >>sys.stderr, '\n%s\ninput:' % (self,)
202 print >>sys.stderr, input
203 try:
204 comparison = ''.join(self.compare(expected.splitlines(1),
205 output.splitlines(1)))
206 print >>sys.stderr, '-: expected\n+: output'
207 print >>sys.stderr, comparison
208 except AttributeError: # expected or output not a string
209 # alternative output for non-strings:
210 print >>sys.stderr, 'expected: %r' % expected
211 print >>sys.stderr, 'output: %r' % output
212 raise error
215 class CustomTestSuite(unittest.TestSuite):
218 A collection of CustomTestCases.
220 Provides test suite ID generation and a method for adding test cases.
223 id = ''
224 """Identifier for the TestSuite. Prepended to the
225 TestCase identifiers to make identification easier."""
227 next_test_case_id = 0
228 """The next identifier to use for non-identified test cases."""
230 def __init__(self, tests=(), id=None, suite_settings=None):
232 Initialize the CustomTestSuite.
234 Arguments:
236 id -- identifier for the suite, prepended to test cases.
237 suite_settings -- settings overrides for this test suite.
239 unittest.TestSuite.__init__(self, tests)
240 self.suite_settings = suite_settings or {}
241 if id is None:
242 mypath = os.path.abspath(
243 sys.modules[CustomTestSuite.__module__].__file__)
244 outerframes = inspect.getouterframes(inspect.currentframe())
245 for outerframe in outerframes[1:]:
246 if outerframe[3] != '__init__':
247 callerpath = outerframe[1]
248 if callerpath is None:
249 # It happens sometimes. Why is a mystery.
250 callerpath = os.getcwd()
251 callerpath = os.path.abspath(callerpath)
252 break
253 mydir, myname = os.path.split(mypath)
254 if not mydir:
255 mydir = os.curdir
256 if callerpath.startswith(mydir):
257 self.id = callerpath[len(mydir) + 1:] # caller's module
258 else:
259 self.id = callerpath
260 else:
261 self.id = id
263 def addTestCase(self, test_case_class, method_name, input, expected,
264 id=None, run_in_debugger=0, **kwargs):
266 Create a CustomTestCase in the CustomTestSuite.
267 Also return it, just in case.
269 Arguments:
271 test_case_class -- the CustomTestCase to add
272 method_name -- a string; CustomTestCase.method_name is the test
273 input -- input to the parser.
274 expected -- expected output from the parser.
275 id -- unique test identifier, used by the test framework.
276 run_in_debugger -- if true, run this test under the pdb debugger.
278 if id is None: # generate id if required
279 id = self.next_test_case_id
280 self.next_test_case_id += 1
281 # test identifier will become suiteid.testid
282 tcid = '%s: %s' % (self.id, id)
283 # suite_settings may be passed as a parameter;
284 # if not, set from attribute:
285 kwargs.setdefault('suite_settings', self.suite_settings)
286 # generate and add test case
287 tc = test_case_class(method_name, input, expected, tcid,
288 run_in_debugger=run_in_debugger, **kwargs)
289 self.addTest(tc)
290 return tc
292 def generate_no_tests(self, *args, **kwargs):
293 pass
296 class TransformTestCase(CustomTestCase):
299 Output checker for the transform.
301 Should probably be called TransformOutputChecker, but I can deal with
302 that later when/if someone comes up with a category of transform test
303 cases that have nothing to do with the input and output of the transform.
306 option_parser = frontend.OptionParser(components=(rst.Parser,))
307 settings = option_parser.get_default_values()
308 settings.report_level = 1
309 settings.halt_level = 5
310 settings.debug = package_unittest.debug
311 settings.warning_stream = DevNull()
312 unknown_reference_resolvers = ()
314 def __init__(self, *args, **kwargs):
315 self.transforms = kwargs['transforms']
316 """List of transforms to perform for this test case."""
318 self.parser = kwargs['parser']
319 """Input parser for this test case."""
321 del kwargs['transforms'], kwargs['parser'] # only wanted here
322 CustomTestCase.__init__(self, *args, **kwargs)
324 def supports(self, format):
325 return 1
327 def test_transforms(self):
328 if self.run_in_debugger:
329 pdb.set_trace()
330 settings = self.settings.copy()
331 settings.__dict__.update(self.suite_settings)
332 document = utils.new_document('test data', settings)
333 self.parser.parse(self.input, document)
334 # Don't do a ``populate_from_components()`` because that would
335 # enable the Transformer's default transforms.
336 document.transformer.add_transforms(self.transforms)
337 document.transformer.add_transform(universal.TestMessages)
338 document.transformer.components['writer'] = self
339 document.transformer.apply_transforms()
340 output = document.pformat()
341 self.compare_output(self.input, output, self.expected)
343 def test_transforms_verbosely(self):
344 if self.run_in_debugger:
345 pdb.set_trace()
346 print '\n', self.id
347 print '-' * 70
348 print self.input
349 settings = self.settings.copy()
350 settings.__dict__.update(self.suite_settings)
351 document = utils.new_document('test data', settings)
352 self.parser.parse(self.input, document)
353 print '-' * 70
354 print document.pformat()
355 for transformClass in self.transforms:
356 transformClass(document).apply()
357 output = document.pformat()
358 print '-' * 70
359 print output
360 self.compare_output(self.input, output, self.expected)
363 class TransformTestSuite(CustomTestSuite):
366 A collection of TransformTestCases.
368 A TransformTestSuite instance manufactures TransformTestCases,
369 keeps track of them, and provides a shared test fixture (a-la
370 setUp and tearDown).
373 def __init__(self, parser, suite_settings=None):
374 self.parser = parser
375 """Parser shared by all test cases."""
377 CustomTestSuite.__init__(self, suite_settings=suite_settings)
379 def generateTests(self, dict, dictname='totest',
380 testmethod='test_transforms'):
382 Stock the suite with test cases generated from a test data dictionary.
384 Each dictionary key (test type's name) maps to a tuple, whose
385 first item is a list of transform classes and whose second
386 item is a list of tests. Each test is a list: input, expected
387 output, optional modifier. The optional third entry, a
388 behavior modifier, can be 0 (temporarily disable this test) or
389 1 (run this test under the pdb debugger). Tests should be
390 self-documenting and not require external comments.
392 for name, (transforms, cases) in dict.items():
393 for casenum in range(len(cases)):
394 case = cases[casenum]
395 run_in_debugger = 0
396 if len(case)==3:
397 # TODO: (maybe) change the 3rd argument to a dict, so it
398 # can handle more cases by keyword ('disable', 'debug',
399 # 'settings'), here and in other generateTests methods.
400 # But there's also the method that
401 # HtmlPublishPartsTestSuite uses <DJG>
402 if case[2]:
403 run_in_debugger = 1
404 else:
405 continue
406 self.addTestCase(
407 TransformTestCase, testmethod,
408 transforms=transforms, parser=self.parser,
409 input=case[0], expected=case[1],
410 id='%s[%r][%s]' % (dictname, name, casenum),
411 run_in_debugger=run_in_debugger)
414 class ParserTestCase(CustomTestCase):
417 Output checker for the parser.
419 Should probably be called ParserOutputChecker, but I can deal with
420 that later when/if someone comes up with a category of parser test
421 cases that have nothing to do with the input and output of the parser.
424 parser = rst.Parser()
425 """Parser shared by all ParserTestCases."""
427 option_parser = frontend.OptionParser(components=(rst.Parser,))
428 settings = option_parser.get_default_values()
429 settings.report_level = 5
430 settings.halt_level = 5
431 settings.debug = package_unittest.debug
433 def test_parser(self):
434 if self.run_in_debugger:
435 pdb.set_trace()
436 settings = self.settings.copy()
437 settings.__dict__.update(self.suite_settings)
438 document = utils.new_document('test data', settings)
439 self.parser.parse(self.input, document)
440 output = document.pformat()
441 self.compare_output(self.input, output, self.expected)
444 class ParserTestSuite(CustomTestSuite):
447 A collection of ParserTestCases.
449 A ParserTestSuite instance manufactures ParserTestCases,
450 keeps track of them, and provides a shared test fixture (a-la
451 setUp and tearDown).
454 test_case_class = ParserTestCase
456 def generateTests(self, dict, dictname='totest'):
458 Stock the suite with test cases generated from a test data dictionary.
460 Each dictionary key (test type name) maps to a list of tests. Each
461 test is a list: input, expected output, optional modifier. The
462 optional third entry, a behavior modifier, can be 0 (temporarily
463 disable this test) or 1 (run this test under the pdb debugger). Tests
464 should be self-documenting and not require external comments.
466 for name, cases in dict.items():
467 for casenum in range(len(cases)):
468 case = cases[casenum]
469 run_in_debugger = 0
470 if len(case)==3:
471 if case[2]:
472 run_in_debugger = 1
473 else:
474 continue
475 self.addTestCase(
476 self.test_case_class, 'test_parser',
477 input=case[0], expected=case[1],
478 id='%s[%r][%s]' % (dictname, name, casenum),
479 run_in_debugger=run_in_debugger)
482 class PEPParserTestCase(ParserTestCase):
484 """PEP-specific parser test case."""
486 parser = rst.Parser(rfc2822=1, inliner=rst.states.Inliner())
487 """Parser shared by all PEPParserTestCases."""
489 option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
490 settings = option_parser.get_default_values()
491 settings.report_level = 5
492 settings.halt_level = 5
493 settings.debug = package_unittest.debug
496 class PEPParserTestSuite(ParserTestSuite):
498 """A collection of PEPParserTestCases."""
500 test_case_class = PEPParserTestCase
503 class GridTableParserTestCase(CustomTestCase):
505 parser = tableparser.GridTableParser()
507 def test_parse_table(self):
508 self.parser.setup(StringList(string2lines(self.input), 'test data'))
509 try:
510 self.parser.find_head_body_sep()
511 self.parser.parse_table()
512 output = self.parser.cells
513 except Exception, details:
514 output = '%s: %s' % (details.__class__.__name__, details)
515 self.compare_output(self.input, pformat(output) + '\n',
516 pformat(self.expected) + '\n')
518 def test_parse(self):
519 try:
520 output = self.parser.parse(StringList(string2lines(self.input),
521 'test data'))
522 except Exception, details:
523 output = '%s: %s' % (details.__class__.__name__, details)
524 self.compare_output(self.input, pformat(output) + '\n',
525 pformat(self.expected) + '\n')
528 class GridTableParserTestSuite(CustomTestSuite):
531 A collection of GridTableParserTestCases.
533 A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
534 keeps track of them, and provides a shared test fixture (a-la setUp and
535 tearDown).
538 test_case_class = GridTableParserTestCase
540 def generateTests(self, dict, dictname='totest'):
542 Stock the suite with test cases generated from a test data dictionary.
544 Each dictionary key (test type name) maps to a list of tests. Each
545 test is a list: an input table, expected output from parse_table(),
546 expected output from parse(), optional modifier. The optional fourth
547 entry, a behavior modifier, can be 0 (temporarily disable this test)
548 or 1 (run this test under the pdb debugger). Tests should be
549 self-documenting and not require external comments.
551 for name, cases in dict.items():
552 for casenum in range(len(cases)):
553 case = cases[casenum]
554 run_in_debugger = 0
555 if len(case) == 4:
556 if case[-1]:
557 run_in_debugger = 1
558 else:
559 continue
560 self.addTestCase(self.test_case_class, 'test_parse_table',
561 input=case[0], expected=case[1],
562 id='%s[%r][%s]' % (dictname, name, casenum),
563 run_in_debugger=run_in_debugger)
564 self.addTestCase(self.test_case_class, 'test_parse',
565 input=case[0], expected=case[2],
566 id='%s[%r][%s]' % (dictname, name, casenum),
567 run_in_debugger=run_in_debugger)
570 class SimpleTableParserTestCase(GridTableParserTestCase):
572 parser = tableparser.SimpleTableParser()
575 class SimpleTableParserTestSuite(CustomTestSuite):
578 A collection of SimpleTableParserTestCases.
581 test_case_class = SimpleTableParserTestCase
583 def generateTests(self, dict, dictname='totest'):
585 Stock the suite with test cases generated from a test data dictionary.
587 Each dictionary key (test type name) maps to a list of tests. Each
588 test is a list: an input table, expected output from parse(), optional
589 modifier. The optional third entry, a behavior modifier, can be 0
590 (temporarily disable this test) or 1 (run this test under the pdb
591 debugger). Tests should be self-documenting and not require external
592 comments.
594 for name, cases in dict.items():
595 for casenum in range(len(cases)):
596 case = cases[casenum]
597 run_in_debugger = 0
598 if len(case) == 3:
599 if case[-1]:
600 run_in_debugger = 1
601 else:
602 continue
603 self.addTestCase(self.test_case_class, 'test_parse',
604 input=case[0], expected=case[1],
605 id='%s[%r][%s]' % (dictname, name, casenum),
606 run_in_debugger=run_in_debugger)
609 class PythonModuleParserTestCase(CustomTestCase):
611 def test_parser(self):
612 if self.run_in_debugger:
613 pdb.set_trace()
614 module = moduleparser.parse_module(self.input, 'test data').pformat()
615 output = str(module)
616 self.compare_output(self.input, output, self.expected)
618 def test_token_parser_rhs(self):
619 if self.run_in_debugger:
620 pdb.set_trace()
621 tr = moduleparser.TokenParser(self.input)
622 output = tr.rhs(1)
623 self.compare_output(self.input, output, self.expected)
626 class PythonModuleParserTestSuite(CustomTestSuite):
629 A collection of PythonModuleParserTestCase.
632 def generateTests(self, dict, dictname='totest',
633 testmethod='test_parser'):
635 Stock the suite with test cases generated from a test data dictionary.
637 Each dictionary key (test type's name) maps to a list of tests. Each
638 test is a list: input, expected output, optional modifier. The
639 optional third entry, a behavior modifier, can be 0 (temporarily
640 disable this test) or 1 (run this test under the pdb debugger). Tests
641 should be self-documenting and not require external comments.
643 for name, cases in dict.items():
644 for casenum in range(len(cases)):
645 case = cases[casenum]
646 run_in_debugger = 0
647 if len(case)==3:
648 if case[2]:
649 run_in_debugger = 1
650 else:
651 continue
652 self.addTestCase(
653 PythonModuleParserTestCase, testmethod,
654 input=case[0], expected=case[1],
655 id='%s[%r][%s]' % (dictname, name, casenum),
656 run_in_debugger=run_in_debugger)
659 class WriterPublishTestCase(CustomTestCase, docutils.SettingsSpec):
662 Test case for publish.
665 settings_default_overrides = {'_disable_config': 1,
666 'strict_visitor': 1}
667 writer_name = '' # set in subclasses or constructor
669 def __init__(self, *args, **kwargs):
670 if 'writer_name' in kwargs:
671 self.writer_name = kwargs['writer_name']
672 del kwargs['writer_name']
673 CustomTestCase.__init__(self, *args, **kwargs)
675 def test_publish(self):
676 if self.run_in_debugger:
677 pdb.set_trace()
678 output = docutils.core.publish_string(
679 source=self.input,
680 reader_name='standalone',
681 parser_name='restructuredtext',
682 writer_name=self.writer_name,
683 settings_spec=self,
684 settings_overrides=self.suite_settings)
685 self.compare_output(self.input, output, self.expected)
688 class PublishTestSuite(CustomTestSuite):
690 def __init__(self, writer_name, suite_settings=None):
692 `writer_name` is the name of the writer to use.
694 CustomTestSuite.__init__(self, suite_settings=suite_settings)
695 self.test_class = WriterPublishTestCase
696 self.writer_name = writer_name
698 def generateTests(self, dict, dictname='totest'):
699 for name, cases in dict.items():
700 for casenum in range(len(cases)):
701 case = cases[casenum]
702 run_in_debugger = 0
703 if len(case)==3:
704 if case[2]:
705 run_in_debugger = 1
706 else:
707 continue
708 self.addTestCase(
709 self.test_class, 'test_publish',
710 input=case[0], expected=case[1],
711 id='%s[%r][%s]' % (dictname, name, casenum),
712 run_in_debugger=run_in_debugger,
713 # Passed to constructor of self.test_class:
714 writer_name=self.writer_name)
717 class HtmlPublishPartsTestSuite(CustomTestSuite):
719 def generateTests(self, dict, dictname='totest'):
720 for name, (settings_overrides, cases) in dict.items():
721 settings = self.suite_settings.copy()
722 settings.update(settings_overrides)
723 for casenum in range(len(cases)):
724 case = cases[casenum]
725 run_in_debugger = 0
726 if len(case)==3:
727 if case[2]:
728 run_in_debugger = 1
729 else:
730 continue
731 self.addTestCase(
732 HtmlWriterPublishPartsTestCase, 'test_publish',
733 input=case[0], expected=case[1],
734 id='%s[%r][%s]' % (dictname, name, casenum),
735 run_in_debugger=run_in_debugger,
736 suite_settings=settings)
739 class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
742 Test case for HTML writer via the publish_parts interface.
745 writer_name = 'html'
747 settings_default_overrides = \
748 WriterPublishTestCase.settings_default_overrides.copy()
749 settings_default_overrides['stylesheet'] = ''
751 def test_publish(self):
752 if self.run_in_debugger:
753 pdb.set_trace()
754 parts = docutils.core.publish_parts(
755 source=self.input,
756 reader_name='standalone',
757 parser_name='restructuredtext',
758 writer_name=self.writer_name,
759 settings_spec=self,
760 settings_overrides=self.suite_settings)
761 output = self.format_output(parts)
762 # interpolate standard variables:
763 expected = self.expected % {'version': docutils.__version__}
764 self.compare_output(self.input, output, expected)
766 standard_content_type_template = ('<meta http-equiv="Content-Type"'
767 ' content="text/html; charset=%s" />\n')
768 standard_generator_template = (
769 '<meta name="generator"'
770 ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
771 standard_html_meta_value = (
772 standard_content_type_template
773 + standard_generator_template % docutils.__version__)
774 standard_meta_value = standard_html_meta_value % 'utf-8'
775 standard_html_prolog = """\
776 <?xml version="1.0" encoding="%s" ?>
777 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
780 def format_output(self, parts):
781 """Minimize & standardize the output."""
782 # remove redundant parts & uninteresting parts:
783 del parts['whole']
784 assert parts['body'] == parts['fragment']
785 del parts['body']
786 del parts['body_pre_docinfo']
787 del parts['body_prefix']
788 del parts['body_suffix']
789 del parts['head']
790 del parts['head_prefix']
791 del parts['encoding']
792 del parts['version']
793 # remove standard portions:
794 parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
795 parts['html_head'] = parts['html_head'].replace(
796 self.standard_html_meta_value, '...')
797 parts['html_prolog'] = parts['html_prolog'].replace(
798 self.standard_html_prolog, '')
799 # remove empty values:
800 for key in parts.keys():
801 if not parts[key]:
802 del parts[key]
803 # standard output format:
804 keys = parts.keys()
805 keys.sort()
806 output = []
807 for key in keys:
808 output.append("%r: '''%s'''"
809 % (key, parts[key].encode('raw_unicode_escape')))
810 if output[-1].endswith("\n'''"):
811 output[-1] = output[-1][:-4] + "\\n'''"
812 return '{' + ',\n '.join(output) + '}\n'
815 def exception_data(code):
817 Execute `code` and return the resulting exception, the exception arguments,
818 and the formatted exception string.
820 try:
821 exec(code)
822 except Exception, detail:
823 return (detail, detail.args,
824 '%s: %s' % (detail.__class__.__name__, detail))
827 def _format_str(*args):
828 r"""
829 Return a tuple containing representations of all args.
831 Same as map(repr, args) except that it returns multi-line
832 representations for strings containing newlines, e.g.::
834 '''\
835 foo \n\
838 baz'''
840 instead of::
842 'foo \nbar\n\nbaz'
844 This is a helper function for CustomTestCase.
846 return_tuple = []
847 for i in args:
848 r = repr(i)
849 if ( (isinstance(i, str) or isinstance(i, unicode))
850 and '\n' in i):
851 stripped = ''
852 if isinstance(i, unicode):
853 # stripped = 'u' or 'U'
854 stripped = r[0]
855 r = r[1:]
856 # quote_char = "'" or '"'
857 quote_char = r[0]
858 assert quote_char in ("'", '"')
859 assert r[0] == r[-1]
860 r = r[1:-1]
861 r = (stripped + 3 * quote_char + '\\\n' +
862 re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
863 3 * quote_char)
864 r = re.sub(r' \n', r' \\n\\\n', r)
865 return_tuple.append(r)
866 return tuple(return_tuple)