fix snapshot creation, and put snapshots on sourceforge.net directly (not via ftp...
[docutils.git] / docutils / test / DocutilsTestSupport.py
blobce67ab2622a53b6b547cdf5de7b06276647d3a8c
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
50 from types import UnicodeType, StringType
52 testroot = os.path.abspath(os.path.dirname(__file__) or os.curdir)
53 os.chdir(testroot)
54 sys.path.insert(0, os.path.normpath(os.path.join(testroot, '..')))
55 sys.path.insert(0, testroot)
56 sys.path.append(os.path.normpath(os.path.join(testroot, '..', 'extras')))
58 try:
59 import docutils_difflib
60 import package_unittest
61 import docutils
62 import docutils.core
63 from docutils import frontend, nodes, statemachine, urischemes, utils
64 from docutils.transforms import universal
65 from docutils.parsers import rst
66 from docutils.parsers.rst import states, tableparser, roles, languages
67 from docutils.readers import standalone, pep
68 from docutils.readers.python import moduleparser
69 from docutils.statemachine import StringList, string2lines
70 except ImportError:
71 # The importing module (usually __init__.py in one of the
72 # subdirectories) may catch ImportErrors in order to detect the
73 # absence of DocutilsTestSupport in sys.path. Thus, ImportErrors
74 # resulting from problems with importing Docutils modules must
75 # caught here.
76 traceback.print_exc()
77 sys.exit(1)
80 try:
81 import mypdb as pdb
82 except:
83 import pdb
86 # Hack to make repr(StringList) look like repr(list):
87 StringList.__repr__ = StringList.__str__
90 class DevNull:
92 """Output sink."""
94 def write(self, string):
95 pass
97 def close(self):
98 pass
101 class StandardTestCase(unittest.TestCase):
104 Helper class, providing the same interface as unittest.TestCase,
105 but with useful setUp and comparison methods.
108 def setUp(self):
109 os.chdir(testroot)
111 def failUnlessEqual(self, first, second, msg=None):
112 """Fail if the two objects are unequal as determined by the '=='
113 operator.
115 if not first == second:
116 raise self.failureException, \
117 (msg or '%s != %s' % _format_str(first, second))
119 def failIfEqual(self, first, second, msg=None):
120 """Fail if the two objects are equal as determined by the '=='
121 operator.
123 if first == second:
124 raise self.failureException, \
125 (msg or '%s == %s' % _format_str(first, second))
127 # Synonyms for assertion methods
129 assertEqual = assertEquals = failUnlessEqual
131 assertNotEqual = assertNotEquals = failIfEqual
134 class CustomTestCase(StandardTestCase):
137 Helper class, providing extended functionality over unittest.TestCase.
139 The methods failUnlessEqual and failIfEqual have been overwritten
140 to provide better support for multi-line strings. Furthermore,
141 see the compare_output method and the parameter list of __init__.
144 compare = docutils_difflib.Differ().compare
145 """Comparison method shared by all subclasses."""
147 def __init__(self, method_name, input, expected, id, run_in_debugger=0,
148 suite_settings=None):
150 Initialise the CustomTestCase.
152 Arguments:
154 method_name -- name of test method to run.
155 input -- input to the parser.
156 expected -- expected output from the parser.
157 id -- unique test identifier, used by the test framework.
158 run_in_debugger -- if true, run this test under the pdb debugger.
159 suite_settings -- settings overrides for this test suite.
161 self.id = id
162 self.input = input
163 self.expected = expected
164 self.run_in_debugger = run_in_debugger
165 self.suite_settings = suite_settings.copy() or {}
167 # Ring your mother.
168 unittest.TestCase.__init__(self, method_name)
170 def __str__(self):
172 Return string conversion. Overridden to give test id, in addition to
173 method name.
175 return '%s; %s' % (self.id, unittest.TestCase.__str__(self))
177 def __repr__(self):
178 return "<%s %s>" % (self.id, unittest.TestCase.__repr__(self))
180 def clear_roles(self):
181 # Language-specific roles and roles added by the
182 # "default-role" and "role" directives are currently stored
183 # globally in the roles._roles dictionary. This workaround
184 # empties that dictionary.
185 roles._roles = {}
187 def setUp(self):
188 StandardTestCase.setUp(self)
189 self.clear_roles()
191 def compare_output(self, input, output, expected):
192 """`input`, `output`, and `expected` should all be strings."""
193 if isinstance(input, UnicodeType):
194 input = input.encode('raw_unicode_escape')
195 if isinstance(output, UnicodeType):
196 output = output.encode('raw_unicode_escape')
197 if isinstance(expected, UnicodeType):
198 expected = expected.encode('raw_unicode_escape')
199 try:
200 self.assertEquals(output, expected)
201 except AssertionError, error:
202 print >>sys.stderr, '\n%s\ninput:' % (self,)
203 print >>sys.stderr, input
204 try:
205 comparison = ''.join(self.compare(expected.splitlines(1),
206 output.splitlines(1)))
207 print >>sys.stderr, '-: expected\n+: output'
208 print >>sys.stderr, comparison
209 except AttributeError: # expected or output not a string
210 # alternative output for non-strings:
211 print >>sys.stderr, 'expected: %r' % expected
212 print >>sys.stderr, 'output: %r' % output
213 raise error
216 class CustomTestSuite(unittest.TestSuite):
219 A collection of CustomTestCases.
221 Provides test suite ID generation and a method for adding test cases.
224 id = ''
225 """Identifier for the TestSuite. Prepended to the
226 TestCase identifiers to make identification easier."""
228 next_test_case_id = 0
229 """The next identifier to use for non-identified test cases."""
231 def __init__(self, tests=(), id=None, suite_settings=None):
233 Initialize the CustomTestSuite.
235 Arguments:
237 id -- identifier for the suite, prepended to test cases.
238 suite_settings -- settings overrides for this test suite.
240 unittest.TestSuite.__init__(self, tests)
241 self.suite_settings = suite_settings or {}
242 if id is None:
243 mypath = os.path.abspath(
244 sys.modules[CustomTestSuite.__module__].__file__)
245 outerframes = inspect.getouterframes(inspect.currentframe())
246 for outerframe in outerframes[1:]:
247 if outerframe[3] != '__init__':
248 callerpath = outerframe[1]
249 if callerpath is None:
250 # It happens sometimes. Why is a mystery.
251 callerpath = os.getcwd()
252 callerpath = os.path.abspath(callerpath)
253 break
254 mydir, myname = os.path.split(mypath)
255 if not mydir:
256 mydir = os.curdir
257 if callerpath.startswith(mydir):
258 self.id = callerpath[len(mydir) + 1:] # caller's module
259 else:
260 self.id = callerpath
261 else:
262 self.id = id
264 def addTestCase(self, test_case_class, method_name, input, expected,
265 id=None, run_in_debugger=0, **kwargs):
267 Create a CustomTestCase in the CustomTestSuite.
268 Also return it, just in case.
270 Arguments:
272 test_case_class -- the CustomTestCase to add
273 method_name -- a string; CustomTestCase.method_name is the test
274 input -- input to the parser.
275 expected -- expected output from the parser.
276 id -- unique test identifier, used by the test framework.
277 run_in_debugger -- if true, run this test under the pdb debugger.
279 if id is None: # generate id if required
280 id = self.next_test_case_id
281 self.next_test_case_id += 1
282 # test identifier will become suiteid.testid
283 tcid = '%s: %s' % (self.id, id)
284 # suite_settings may be passed as a parameter;
285 # if not, set from attribute:
286 kwargs.setdefault('suite_settings', self.suite_settings)
287 # generate and add test case
288 tc = test_case_class(method_name, input, expected, tcid,
289 run_in_debugger=run_in_debugger, **kwargs)
290 self.addTest(tc)
291 return tc
293 def generate_no_tests(self, *args, **kwargs):
294 pass
297 class TransformTestCase(CustomTestCase):
300 Output checker for the transform.
302 Should probably be called TransformOutputChecker, but I can deal with
303 that later when/if someone comes up with a category of transform test
304 cases that have nothing to do with the input and output of the transform.
307 option_parser = frontend.OptionParser(components=(rst.Parser,))
308 settings = option_parser.get_default_values()
309 settings.report_level = 1
310 settings.halt_level = 5
311 settings.debug = package_unittest.debug
312 settings.warning_stream = DevNull()
313 unknown_reference_resolvers = ()
315 def __init__(self, *args, **kwargs):
316 self.transforms = kwargs['transforms']
317 """List of transforms to perform for this test case."""
319 self.parser = kwargs['parser']
320 """Input parser for this test case."""
322 del kwargs['transforms'], kwargs['parser'] # only wanted here
323 CustomTestCase.__init__(self, *args, **kwargs)
325 def supports(self, format):
326 return 1
328 def test_transforms(self):
329 if self.run_in_debugger:
330 pdb.set_trace()
331 settings = self.settings.copy()
332 settings.__dict__.update(self.suite_settings)
333 document = utils.new_document('test data', settings)
334 self.parser.parse(self.input, document)
335 # Don't do a ``populate_from_components()`` because that would
336 # enable the Transformer's default transforms.
337 document.transformer.add_transforms(self.transforms)
338 document.transformer.add_transform(universal.TestMessages)
339 document.transformer.components['writer'] = self
340 document.transformer.apply_transforms()
341 output = document.pformat()
342 self.compare_output(self.input, output, self.expected)
344 def test_transforms_verbosely(self):
345 if self.run_in_debugger:
346 pdb.set_trace()
347 print '\n', self.id
348 print '-' * 70
349 print self.input
350 settings = self.settings.copy()
351 settings.__dict__.update(self.suite_settings)
352 document = utils.new_document('test data', settings)
353 self.parser.parse(self.input, document)
354 print '-' * 70
355 print document.pformat()
356 for transformClass in self.transforms:
357 transformClass(document).apply()
358 output = document.pformat()
359 print '-' * 70
360 print output
361 self.compare_output(self.input, output, self.expected)
364 class TransformTestSuite(CustomTestSuite):
367 A collection of TransformTestCases.
369 A TransformTestSuite instance manufactures TransformTestCases,
370 keeps track of them, and provides a shared test fixture (a-la
371 setUp and tearDown).
374 def __init__(self, parser, suite_settings=None):
375 self.parser = parser
376 """Parser shared by all test cases."""
378 CustomTestSuite.__init__(self, suite_settings=suite_settings)
380 def generateTests(self, dict, dictname='totest',
381 testmethod='test_transforms'):
383 Stock the suite with test cases generated from a test data dictionary.
385 Each dictionary key (test type's name) maps to a tuple, whose
386 first item is a list of transform classes and whose second
387 item is a list of tests. Each test is a list: input, expected
388 output, optional modifier. The optional third entry, a
389 behavior modifier, can be 0 (temporarily disable this test) or
390 1 (run this test under the pdb debugger). Tests should be
391 self-documenting and not require external comments.
393 for name, (transforms, cases) in dict.items():
394 for casenum in range(len(cases)):
395 case = cases[casenum]
396 run_in_debugger = 0
397 if len(case)==3:
398 # TODO: (maybe) change the 3rd argument to a dict, so it
399 # can handle more cases by keyword ('disable', 'debug',
400 # 'settings'), here and in other generateTests methods.
401 # But there's also the method that
402 # HtmlPublishPartsTestSuite uses <DJG>
403 if case[2]:
404 run_in_debugger = 1
405 else:
406 continue
407 self.addTestCase(
408 TransformTestCase, testmethod,
409 transforms=transforms, parser=self.parser,
410 input=case[0], expected=case[1],
411 id='%s[%r][%s]' % (dictname, name, casenum),
412 run_in_debugger=run_in_debugger)
415 class ParserTestCase(CustomTestCase):
418 Output checker for the parser.
420 Should probably be called ParserOutputChecker, but I can deal with
421 that later when/if someone comes up with a category of parser test
422 cases that have nothing to do with the input and output of the parser.
425 parser = rst.Parser()
426 """Parser shared by all ParserTestCases."""
428 option_parser = frontend.OptionParser(components=(rst.Parser,))
429 settings = option_parser.get_default_values()
430 settings.report_level = 5
431 settings.halt_level = 5
432 settings.debug = package_unittest.debug
434 def test_parser(self):
435 if self.run_in_debugger:
436 pdb.set_trace()
437 settings = self.settings.copy()
438 settings.__dict__.update(self.suite_settings)
439 document = utils.new_document('test data', settings)
440 self.parser.parse(self.input, document)
441 output = document.pformat()
442 self.compare_output(self.input, output, self.expected)
445 class ParserTestSuite(CustomTestSuite):
448 A collection of ParserTestCases.
450 A ParserTestSuite instance manufactures ParserTestCases,
451 keeps track of them, and provides a shared test fixture (a-la
452 setUp and tearDown).
455 test_case_class = ParserTestCase
457 def generateTests(self, dict, dictname='totest'):
459 Stock the suite with test cases generated from a test data dictionary.
461 Each dictionary key (test type name) maps to a list of tests. Each
462 test is a list: input, expected output, optional modifier. The
463 optional third entry, a behavior modifier, can be 0 (temporarily
464 disable this test) or 1 (run this test under the pdb debugger). Tests
465 should be self-documenting and not require external comments.
467 for name, cases in dict.items():
468 for casenum in range(len(cases)):
469 case = cases[casenum]
470 run_in_debugger = 0
471 if len(case)==3:
472 if case[2]:
473 run_in_debugger = 1
474 else:
475 continue
476 self.addTestCase(
477 self.test_case_class, 'test_parser',
478 input=case[0], expected=case[1],
479 id='%s[%r][%s]' % (dictname, name, casenum),
480 run_in_debugger=run_in_debugger)
483 class PEPParserTestCase(ParserTestCase):
485 """PEP-specific parser test case."""
487 parser = rst.Parser(rfc2822=1, inliner=rst.states.Inliner())
488 """Parser shared by all PEPParserTestCases."""
490 option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
491 settings = option_parser.get_default_values()
492 settings.report_level = 5
493 settings.halt_level = 5
494 settings.debug = package_unittest.debug
497 class PEPParserTestSuite(ParserTestSuite):
499 """A collection of PEPParserTestCases."""
501 test_case_class = PEPParserTestCase
504 class GridTableParserTestCase(CustomTestCase):
506 parser = tableparser.GridTableParser()
508 def test_parse_table(self):
509 self.parser.setup(StringList(string2lines(self.input), 'test data'))
510 try:
511 self.parser.find_head_body_sep()
512 self.parser.parse_table()
513 output = self.parser.cells
514 except Exception, details:
515 output = '%s: %s' % (details.__class__.__name__, details)
516 self.compare_output(self.input, pformat(output) + '\n',
517 pformat(self.expected) + '\n')
519 def test_parse(self):
520 try:
521 output = self.parser.parse(StringList(string2lines(self.input),
522 'test data'))
523 except Exception, details:
524 output = '%s: %s' % (details.__class__.__name__, details)
525 self.compare_output(self.input, pformat(output) + '\n',
526 pformat(self.expected) + '\n')
529 class GridTableParserTestSuite(CustomTestSuite):
532 A collection of GridTableParserTestCases.
534 A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
535 keeps track of them, and provides a shared test fixture (a-la setUp and
536 tearDown).
539 test_case_class = GridTableParserTestCase
541 def generateTests(self, dict, dictname='totest'):
543 Stock the suite with test cases generated from a test data dictionary.
545 Each dictionary key (test type name) maps to a list of tests. Each
546 test is a list: an input table, expected output from parse_table(),
547 expected output from parse(), optional modifier. The optional fourth
548 entry, a behavior modifier, can be 0 (temporarily disable this test)
549 or 1 (run this test under the pdb debugger). Tests should be
550 self-documenting and not require external comments.
552 for name, cases in dict.items():
553 for casenum in range(len(cases)):
554 case = cases[casenum]
555 run_in_debugger = 0
556 if len(case) == 4:
557 if case[-1]:
558 run_in_debugger = 1
559 else:
560 continue
561 self.addTestCase(self.test_case_class, 'test_parse_table',
562 input=case[0], expected=case[1],
563 id='%s[%r][%s]' % (dictname, name, casenum),
564 run_in_debugger=run_in_debugger)
565 self.addTestCase(self.test_case_class, 'test_parse',
566 input=case[0], expected=case[2],
567 id='%s[%r][%s]' % (dictname, name, casenum),
568 run_in_debugger=run_in_debugger)
571 class SimpleTableParserTestCase(GridTableParserTestCase):
573 parser = tableparser.SimpleTableParser()
576 class SimpleTableParserTestSuite(CustomTestSuite):
579 A collection of SimpleTableParserTestCases.
582 test_case_class = SimpleTableParserTestCase
584 def generateTests(self, dict, dictname='totest'):
586 Stock the suite with test cases generated from a test data dictionary.
588 Each dictionary key (test type name) maps to a list of tests. Each
589 test is a list: an input table, expected output from parse(), optional
590 modifier. The optional third entry, a behavior modifier, can be 0
591 (temporarily disable this test) or 1 (run this test under the pdb
592 debugger). Tests should be self-documenting and not require external
593 comments.
595 for name, cases in dict.items():
596 for casenum in range(len(cases)):
597 case = cases[casenum]
598 run_in_debugger = 0
599 if len(case) == 3:
600 if case[-1]:
601 run_in_debugger = 1
602 else:
603 continue
604 self.addTestCase(self.test_case_class, 'test_parse',
605 input=case[0], expected=case[1],
606 id='%s[%r][%s]' % (dictname, name, casenum),
607 run_in_debugger=run_in_debugger)
610 class PythonModuleParserTestCase(CustomTestCase):
612 def test_parser(self):
613 if self.run_in_debugger:
614 pdb.set_trace()
615 module = moduleparser.parse_module(self.input, 'test data').pformat()
616 output = str(module)
617 self.compare_output(self.input, output, self.expected)
619 def test_token_parser_rhs(self):
620 if self.run_in_debugger:
621 pdb.set_trace()
622 tr = moduleparser.TokenParser(self.input)
623 output = tr.rhs(1)
624 self.compare_output(self.input, output, self.expected)
627 class PythonModuleParserTestSuite(CustomTestSuite):
630 A collection of PythonModuleParserTestCase.
633 def generateTests(self, dict, dictname='totest',
634 testmethod='test_parser'):
636 Stock the suite with test cases generated from a test data dictionary.
638 Each dictionary key (test type's name) maps to a list of tests. Each
639 test is a list: input, expected output, optional modifier. The
640 optional third entry, a behavior modifier, can be 0 (temporarily
641 disable this test) or 1 (run this test under the pdb debugger). Tests
642 should be self-documenting and not require external comments.
644 for name, cases in dict.items():
645 for casenum in range(len(cases)):
646 case = cases[casenum]
647 run_in_debugger = 0
648 if len(case)==3:
649 if case[2]:
650 run_in_debugger = 1
651 else:
652 continue
653 self.addTestCase(
654 PythonModuleParserTestCase, testmethod,
655 input=case[0], expected=case[1],
656 id='%s[%r][%s]' % (dictname, name, casenum),
657 run_in_debugger=run_in_debugger)
660 class WriterPublishTestCase(CustomTestCase, docutils.SettingsSpec):
663 Test case for publish.
666 settings_default_overrides = {'_disable_config': 1,
667 'strict_visitor': 1}
668 writer_name = '' # set in subclasses or constructor
670 def __init__(self, *args, **kwargs):
671 if 'writer_name' in kwargs:
672 self.writer_name = kwargs['writer_name']
673 del kwargs['writer_name']
674 CustomTestCase.__init__(self, *args, **kwargs)
676 def test_publish(self):
677 if self.run_in_debugger:
678 pdb.set_trace()
679 output = docutils.core.publish_string(
680 source=self.input,
681 reader_name='standalone',
682 parser_name='restructuredtext',
683 writer_name=self.writer_name,
684 settings_spec=self,
685 settings_overrides=self.suite_settings)
686 self.compare_output(self.input, output, self.expected)
689 class PublishTestSuite(CustomTestSuite):
691 def __init__(self, writer_name, suite_settings=None):
693 `writer_name` is the name of the writer to use.
695 CustomTestSuite.__init__(self, suite_settings=suite_settings)
696 self.test_class = WriterPublishTestCase
697 self.writer_name = writer_name
699 def generateTests(self, dict, dictname='totest'):
700 for name, cases in dict.items():
701 for casenum in range(len(cases)):
702 case = cases[casenum]
703 run_in_debugger = 0
704 if len(case)==3:
705 if case[2]:
706 run_in_debugger = 1
707 else:
708 continue
709 self.addTestCase(
710 self.test_class, 'test_publish',
711 input=case[0], expected=case[1],
712 id='%s[%r][%s]' % (dictname, name, casenum),
713 run_in_debugger=run_in_debugger,
714 # Passed to constructor of self.test_class:
715 writer_name=self.writer_name)
718 class HtmlPublishPartsTestSuite(CustomTestSuite):
720 def generateTests(self, dict, dictname='totest'):
721 for name, (settings_overrides, cases) in dict.items():
722 settings = self.suite_settings.copy()
723 settings.update(settings_overrides)
724 for casenum in range(len(cases)):
725 case = cases[casenum]
726 run_in_debugger = 0
727 if len(case)==3:
728 if case[2]:
729 run_in_debugger = 1
730 else:
731 continue
732 self.addTestCase(
733 HtmlWriterPublishPartsTestCase, 'test_publish',
734 input=case[0], expected=case[1],
735 id='%s[%r][%s]' % (dictname, name, casenum),
736 run_in_debugger=run_in_debugger,
737 suite_settings=settings)
740 class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
743 Test case for HTML writer via the publish_parts interface.
746 writer_name = 'html'
748 settings_default_overrides = \
749 WriterPublishTestCase.settings_default_overrides.copy()
750 settings_default_overrides['stylesheet'] = ''
752 def test_publish(self):
753 if self.run_in_debugger:
754 pdb.set_trace()
755 parts = docutils.core.publish_parts(
756 source=self.input,
757 reader_name='standalone',
758 parser_name='restructuredtext',
759 writer_name=self.writer_name,
760 settings_spec=self,
761 settings_overrides=self.suite_settings)
762 output = self.format_output(parts)
763 # interpolate standard variables:
764 expected = self.expected % {'version': docutils.__version__}
765 self.compare_output(self.input, output, expected)
767 standard_content_type_template = ('<meta http-equiv="Content-Type"'
768 ' content="text/html; charset=%s" />\n')
769 standard_generator_template = (
770 '<meta name="generator"'
771 ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
772 standard_html_meta_value = (
773 standard_content_type_template
774 + standard_generator_template % docutils.__version__)
775 standard_meta_value = standard_html_meta_value % 'utf-8'
776 standard_html_prolog = """\
777 <?xml version="1.0" encoding="%s" ?>
778 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
781 def format_output(self, parts):
782 """Minimize & standardize the output."""
783 # remove redundant parts & uninteresting parts:
784 del parts['whole']
785 assert parts['body'] == parts['fragment']
786 del parts['body']
787 del parts['body_pre_docinfo']
788 del parts['body_prefix']
789 del parts['body_suffix']
790 del parts['head']
791 del parts['head_prefix']
792 del parts['encoding']
793 del parts['version']
794 # remove standard portions:
795 parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
796 parts['html_head'] = parts['html_head'].replace(
797 self.standard_html_meta_value, '...')
798 parts['html_prolog'] = parts['html_prolog'].replace(
799 self.standard_html_prolog, '')
800 # remove empty values:
801 for key in parts.keys():
802 if not parts[key]:
803 del parts[key]
804 # standard output format:
805 keys = parts.keys()
806 keys.sort()
807 output = []
808 for key in keys:
809 output.append("%r: '''%s'''"
810 % (key, parts[key].encode('raw_unicode_escape')))
811 if output[-1].endswith("\n'''"):
812 output[-1] = output[-1][:-4] + "\\n'''"
813 return '{' + ',\n '.join(output) + '}\n'
816 def exception_data(code):
818 Execute `code` and return the resulting exception, the exception arguments,
819 and the formatted exception string.
821 try:
822 exec(code)
823 except Exception, detail:
824 return (detail, detail.args,
825 '%s: %s' % (detail.__class__.__name__, detail))
828 def _format_str(*args):
829 r"""
830 Return a tuple containing representations of all args.
832 Same as map(repr, args) except that it returns multi-line
833 representations for strings containing newlines, e.g.::
835 '''\
836 foo \n\
839 baz'''
841 instead of::
843 'foo \nbar\n\nbaz'
845 This is a helper function for CustomTestCase.
847 return_tuple = []
848 for i in args:
849 r = repr(i)
850 if ( (isinstance(i, StringType) or isinstance(i, UnicodeType))
851 and '\n' in i):
852 stripped = ''
853 if isinstance(i, UnicodeType):
854 # stripped = 'u' or 'U'
855 stripped = r[0]
856 r = r[1:]
857 # quote_char = "'" or '"'
858 quote_char = r[0]
859 assert quote_char in ("'", '"')
860 assert r[0] == r[-1]
861 r = r[1:-1]
862 r = (stripped + 3 * quote_char + '\\\n' +
863 re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
864 3 * quote_char)
865 r = re.sub(r' \n', r' \\n\\\n', r)
866 return_tuple.append(r)
867 return tuple(return_tuple)