Cleanup: Use True/False for boolean values
[docutils.git] / test / DocutilsTestSupport.py
blob1d1276cca62ff316515522913a8d51b8ec769607
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 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.statemachine import StringList, string2lines
68 from docutils._compat import bytes
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 = difflib.Differ().compare
144 """Comparison method shared by all subclasses."""
146 def __init__(self, method_name, input, expected, id,
147 run_in_debugger=True, 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 sys.version_info > (3,):
195 # API difference: Python 3's node.__str__ doesn't escape
196 #assert expected is None or isinstance(expected, unicode)
197 if isinstance(expected, bytes):
198 expected = expected.decode('utf-8')
199 if isinstance(output, bytes):
200 output = output.decode('utf-8')
201 else:
202 if isinstance(expected, unicode):
203 expected = expected.encode('raw_unicode_escape')
204 if isinstance(output, unicode):
205 output = output.encode('raw_unicode_escape')
206 # Normalize line endings:
207 if expected:
208 expected = '\n'.join(expected.splitlines())
209 if output:
210 output = '\n'.join(output.splitlines())
211 try:
212 self.assertEquals(output, expected)
213 except AssertionError, error:
214 print >>sys.stderr, '\n%s\ninput:' % (self,)
215 print >>sys.stderr, input
216 try:
217 comparison = ''.join(self.compare(expected.splitlines(1),
218 output.splitlines(1)))
219 print >>sys.stderr, '-: expected\n+: output'
220 print >>sys.stderr, comparison
221 except AttributeError: # expected or output not a string
222 # alternative output for non-strings:
223 print >>sys.stderr, 'expected: %r' % expected
224 print >>sys.stderr, 'output: %r' % output
225 raise error
228 class CustomTestSuite(unittest.TestSuite):
231 A collection of CustomTestCases.
233 Provides test suite ID generation and a method for adding test cases.
236 id = ''
237 """Identifier for the TestSuite. Prepended to the
238 TestCase identifiers to make identification easier."""
240 next_test_case_id = 0
241 """The next identifier to use for non-identified test cases."""
243 def __init__(self, tests=(), id=None, suite_settings=None):
245 Initialize the CustomTestSuite.
247 Arguments:
249 id -- identifier for the suite, prepended to test cases.
250 suite_settings -- settings overrides for this test suite.
252 unittest.TestSuite.__init__(self, tests)
253 self.suite_settings = suite_settings or {}
254 if id is None:
255 mypath = os.path.abspath(
256 sys.modules[CustomTestSuite.__module__].__file__)
257 outerframes = inspect.getouterframes(inspect.currentframe())
258 for outerframe in outerframes[1:]:
259 if outerframe[3] != '__init__':
260 callerpath = outerframe[1]
261 if callerpath is None:
262 # It happens sometimes. Why is a mystery.
263 callerpath = os.getcwd()
264 callerpath = os.path.abspath(callerpath)
265 break
266 mydir, myname = os.path.split(mypath)
267 if not mydir:
268 mydir = os.curdir
269 if callerpath.startswith(mydir):
270 self.id = callerpath[len(mydir) + 1:] # caller's module
271 else:
272 self.id = callerpath
273 else:
274 self.id = id
276 def addTestCase(self, test_case_class, method_name, input, expected,
277 id=None, run_in_debugger=False, **kwargs):
279 Create a CustomTestCase in the CustomTestSuite.
280 Also return it, just in case.
282 Arguments:
284 test_case_class -- the CustomTestCase to add
285 method_name -- a string; CustomTestCase.method_name is the test
286 input -- input to the parser.
287 expected -- expected output from the parser.
288 id -- unique test identifier, used by the test framework.
289 run_in_debugger -- if true, run this test under the pdb debugger.
291 if id is None: # generate id if required
292 id = self.next_test_case_id
293 self.next_test_case_id += 1
294 # test identifier will become suiteid.testid
295 tcid = '%s: %s' % (self.id, id)
296 # suite_settings may be passed as a parameter;
297 # if not, set from attribute:
298 kwargs.setdefault('suite_settings', self.suite_settings)
299 # generate and add test case
300 tc = test_case_class(method_name, input, expected, tcid,
301 run_in_debugger=run_in_debugger, **kwargs)
302 self.addTest(tc)
303 return tc
305 def generate_no_tests(self, *args, **kwargs):
306 pass
309 class TransformTestCase(CustomTestCase):
312 Output checker for the transform.
314 Should probably be called TransformOutputChecker, but I can deal with
315 that later when/if someone comes up with a category of transform test
316 cases that have nothing to do with the input and output of the transform.
319 option_parser = frontend.OptionParser(components=(rst.Parser,))
320 settings = option_parser.get_default_values()
321 settings.report_level = 1
322 settings.halt_level = 5
323 settings.debug = package_unittest.debug
324 settings.warning_stream = DevNull()
325 unknown_reference_resolvers = ()
327 def __init__(self, *args, **kwargs):
328 self.transforms = kwargs['transforms']
329 """List of transforms to perform for this test case."""
331 self.parser = kwargs['parser']
332 """Input parser for this test case."""
334 del kwargs['transforms'], kwargs['parser'] # only wanted here
335 CustomTestCase.__init__(self, *args, **kwargs)
337 def supports(self, format):
338 return 1
340 def test_transforms(self):
341 if self.run_in_debugger:
342 pdb.set_trace()
343 settings = self.settings.copy()
344 settings.__dict__.update(self.suite_settings)
345 document = utils.new_document('test data', settings)
346 self.parser.parse(self.input, document)
347 # Don't do a ``populate_from_components()`` because that would
348 # enable the Transformer's default transforms.
349 document.transformer.add_transforms(self.transforms)
350 document.transformer.add_transform(universal.TestMessages)
351 document.transformer.components['writer'] = self
352 document.transformer.apply_transforms()
353 output = document.pformat()
354 self.compare_output(self.input, output, self.expected)
356 def test_transforms_verbosely(self):
357 if self.run_in_debugger:
358 pdb.set_trace()
359 print '\n', self.id
360 print '-' * 70
361 print self.input
362 settings = self.settings.copy()
363 settings.__dict__.update(self.suite_settings)
364 document = utils.new_document('test data', settings)
365 self.parser.parse(self.input, document)
366 print '-' * 70
367 print document.pformat()
368 for transformClass in self.transforms:
369 transformClass(document).apply()
370 output = document.pformat()
371 print '-' * 70
372 print output
373 self.compare_output(self.input, output, self.expected)
376 class TransformTestSuite(CustomTestSuite):
379 A collection of TransformTestCases.
381 A TransformTestSuite instance manufactures TransformTestCases,
382 keeps track of them, and provides a shared test fixture (a-la
383 setUp and tearDown).
386 def __init__(self, parser, suite_settings=None):
387 self.parser = parser
388 """Parser shared by all test cases."""
390 CustomTestSuite.__init__(self, suite_settings=suite_settings)
392 def generateTests(self, dict, dictname='totest',
393 testmethod='test_transforms'):
395 Stock the suite with test cases generated from a test data dictionary.
397 Each dictionary key (test type's name) maps to a tuple, whose
398 first item is a list of transform classes and whose second
399 item is a list of tests. Each test is a list: input, expected
400 output, optional modifier. The optional third entry, a
401 behavior modifier, can be 0 (temporarily disable this test) or
402 1 (run this test under the pdb debugger). Tests should be
403 self-documenting and not require external comments.
405 for name, (transforms, cases) in dict.items():
406 for casenum in range(len(cases)):
407 case = cases[casenum]
408 run_in_debugger = False
409 if len(case)==3:
410 # TODO: (maybe) change the 3rd argument to a dict, so it
411 # can handle more cases by keyword ('disable', 'debug',
412 # 'settings'), here and in other generateTests methods.
413 # But there's also the method that
414 # HtmlPublishPartsTestSuite uses <DJG>
415 if case[2]:
416 run_in_debugger = True
417 else:
418 continue
419 self.addTestCase(
420 TransformTestCase, testmethod,
421 transforms=transforms, parser=self.parser,
422 input=case[0], expected=case[1],
423 id='%s[%r][%s]' % (dictname, name, casenum),
424 run_in_debugger=run_in_debugger)
427 class ParserTestCase(CustomTestCase):
430 Output checker for the parser.
432 Should probably be called ParserOutputChecker, but I can deal with
433 that later when/if someone comes up with a category of parser test
434 cases that have nothing to do with the input and output of the parser.
437 parser = rst.Parser()
438 """Parser shared by all ParserTestCases."""
440 option_parser = frontend.OptionParser(components=(rst.Parser,))
441 settings = option_parser.get_default_values()
442 settings.report_level = 5
443 settings.halt_level = 5
444 settings.debug = package_unittest.debug
446 def test_parser(self):
447 if self.run_in_debugger:
448 pdb.set_trace()
449 settings = self.settings.copy()
450 settings.__dict__.update(self.suite_settings)
451 document = utils.new_document('test data', settings)
452 self.parser.parse(self.input, document)
453 output = document.pformat()
454 self.compare_output(self.input, output, self.expected)
457 class ParserTestSuite(CustomTestSuite):
460 A collection of ParserTestCases.
462 A ParserTestSuite instance manufactures ParserTestCases,
463 keeps track of them, and provides a shared test fixture (a-la
464 setUp and tearDown).
467 test_case_class = ParserTestCase
469 def generateTests(self, dict, dictname='totest'):
471 Stock the suite with test cases generated from a test data dictionary.
473 Each dictionary key (test type name) maps to a list of tests. Each
474 test is a list: input, expected output, optional modifier. The
475 optional third entry, a behavior modifier, can be 0 (temporarily
476 disable this test) or 1 (run this test under the pdb debugger). Tests
477 should be self-documenting and not require external comments.
479 for name, cases in dict.items():
480 for casenum in range(len(cases)):
481 case = cases[casenum]
482 run_in_debugger = False
483 if len(case)==3:
484 if case[2]:
485 run_in_debugger = True
486 else:
487 continue
488 self.addTestCase(
489 self.test_case_class, 'test_parser',
490 input=case[0], expected=case[1],
491 id='%s[%r][%s]' % (dictname, name, casenum),
492 run_in_debugger=run_in_debugger)
495 class PEPParserTestCase(ParserTestCase):
497 """PEP-specific parser test case."""
499 parser = rst.Parser(rfc2822=True, inliner=rst.states.Inliner())
500 """Parser shared by all PEPParserTestCases."""
502 option_parser = frontend.OptionParser(components=(rst.Parser, pep.Reader))
503 settings = option_parser.get_default_values()
504 settings.report_level = 5
505 settings.halt_level = 5
506 settings.debug = package_unittest.debug
509 class PEPParserTestSuite(ParserTestSuite):
511 """A collection of PEPParserTestCases."""
513 test_case_class = PEPParserTestCase
516 class GridTableParserTestCase(CustomTestCase):
518 parser = tableparser.GridTableParser()
520 def test_parse_table(self):
521 self.parser.setup(StringList(string2lines(self.input), 'test data'))
522 try:
523 self.parser.find_head_body_sep()
524 self.parser.parse_table()
525 output = self.parser.cells
526 except Exception, details:
527 output = '%s: %s' % (details.__class__.__name__, details)
528 self.compare_output(self.input, pformat(output) + '\n',
529 pformat(self.expected) + '\n')
531 def test_parse(self):
532 try:
533 output = self.parser.parse(StringList(string2lines(self.input),
534 'test data'))
535 except Exception, details:
536 output = '%s: %s' % (details.__class__.__name__, details)
537 self.compare_output(self.input, pformat(output) + '\n',
538 pformat(self.expected) + '\n')
541 class GridTableParserTestSuite(CustomTestSuite):
544 A collection of GridTableParserTestCases.
546 A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
547 keeps track of them, and provides a shared test fixture (a-la setUp and
548 tearDown).
551 test_case_class = GridTableParserTestCase
553 def generateTests(self, dict, dictname='totest'):
555 Stock the suite with test cases generated from a test data dictionary.
557 Each dictionary key (test type name) maps to a list of tests. Each
558 test is a list: an input table, expected output from parse_table(),
559 expected output from parse(), optional modifier. The optional fourth
560 entry, a behavior modifier, can be 0 (temporarily disable this test)
561 or 1 (run this test under the pdb debugger). Tests should be
562 self-documenting and not require external comments.
564 for name, cases in dict.items():
565 for casenum in range(len(cases)):
566 case = cases[casenum]
567 run_in_debugger = False
568 if len(case) == 4:
569 if case[-1]:
570 run_in_debugger = True
571 else:
572 continue
573 self.addTestCase(self.test_case_class, 'test_parse_table',
574 input=case[0], expected=case[1],
575 id='%s[%r][%s]' % (dictname, name, casenum),
576 run_in_debugger=run_in_debugger)
577 self.addTestCase(self.test_case_class, 'test_parse',
578 input=case[0], expected=case[2],
579 id='%s[%r][%s]' % (dictname, name, casenum),
580 run_in_debugger=run_in_debugger)
583 class SimpleTableParserTestCase(GridTableParserTestCase):
585 parser = tableparser.SimpleTableParser()
588 class SimpleTableParserTestSuite(CustomTestSuite):
591 A collection of SimpleTableParserTestCases.
594 test_case_class = SimpleTableParserTestCase
596 def generateTests(self, dict, dictname='totest'):
598 Stock the suite with test cases generated from a test data dictionary.
600 Each dictionary key (test type name) maps to a list of tests. Each
601 test is a list: an input table, expected output from parse(), optional
602 modifier. The optional third entry, a behavior modifier, can be 0
603 (temporarily disable this test) or 1 (run this test under the pdb
604 debugger). Tests should be self-documenting and not require external
605 comments.
607 for name, cases in dict.items():
608 for casenum in range(len(cases)):
609 case = cases[casenum]
610 run_in_debugger = False
611 if len(case) == 3:
612 if case[-1]:
613 run_in_debugger = True
614 else:
615 continue
616 self.addTestCase(self.test_case_class, 'test_parse',
617 input=case[0], expected=case[1],
618 id='%s[%r][%s]' % (dictname, name, casenum),
619 run_in_debugger=run_in_debugger)
622 class PythonModuleParserTestCase(CustomTestCase):
624 def test_parser(self):
625 if self.run_in_debugger:
626 pdb.set_trace()
627 try:
628 import compiler
629 except ImportError:
630 # skip on Python 3
631 return
632 from docutils.readers.python import moduleparser
633 module = moduleparser.parse_module(self.input, 'test data').pformat()
634 output = str(module)
635 self.compare_output(self.input, output, self.expected)
637 def test_token_parser_rhs(self):
638 if self.run_in_debugger:
639 pdb.set_trace()
640 try:
641 import compiler
642 except ImportError:
643 # skip on Python 3
644 return
645 from docutils.readers.python import moduleparser
646 tr = moduleparser.TokenParser(self.input)
647 output = tr.rhs(1)
648 self.compare_output(self.input, output, self.expected)
651 class PythonModuleParserTestSuite(CustomTestSuite):
654 A collection of PythonModuleParserTestCase.
657 def generateTests(self, dict, dictname='totest',
658 testmethod='test_parser'):
660 Stock the suite with test cases generated from a test data dictionary.
662 Each dictionary key (test type's name) maps to a list of tests. Each
663 test is a list: input, expected output, optional modifier. The
664 optional third entry, a behavior modifier, can be 0 (temporarily
665 disable this test) or 1 (run this test under the pdb debugger). Tests
666 should be self-documenting and not require external comments.
668 for name, cases in dict.items():
669 for casenum in range(len(cases)):
670 case = cases[casenum]
671 run_in_debugger = False
672 if len(case)==3:
673 if case[2]:
674 run_in_debugger = True
675 else:
676 continue
677 self.addTestCase(
678 PythonModuleParserTestCase, testmethod,
679 input=case[0], expected=case[1],
680 id='%s[%r][%s]' % (dictname, name, casenum),
681 run_in_debugger=run_in_debugger)
684 class WriterPublishTestCase(CustomTestCase, docutils.SettingsSpec):
687 Test case for publish.
690 settings_default_overrides = {'_disable_config': 1,
691 'strict_visitor': 1}
692 writer_name = '' # set in subclasses or constructor
694 def __init__(self, *args, **kwargs):
695 if 'writer_name' in kwargs:
696 self.writer_name = kwargs['writer_name']
697 del kwargs['writer_name']
698 CustomTestCase.__init__(self, *args, **kwargs)
700 def test_publish(self):
701 if self.run_in_debugger:
702 pdb.set_trace()
703 output = docutils.core.publish_string(
704 source=self.input,
705 reader_name='standalone',
706 parser_name='restructuredtext',
707 writer_name=self.writer_name,
708 settings_spec=self,
709 settings_overrides=self.suite_settings)
710 self.compare_output(self.input, output, self.expected)
713 class PublishTestSuite(CustomTestSuite):
715 def __init__(self, writer_name, suite_settings=None):
717 `writer_name` is the name of the writer to use.
719 CustomTestSuite.__init__(self, suite_settings=suite_settings)
720 self.test_class = WriterPublishTestCase
721 self.writer_name = writer_name
723 def generateTests(self, dict, dictname='totest'):
724 for name, cases in dict.items():
725 for casenum in range(len(cases)):
726 case = cases[casenum]
727 run_in_debugger = False
728 if len(case)==3:
729 if case[2]:
730 run_in_debugger = True
731 else:
732 continue
733 self.addTestCase(
734 self.test_class, 'test_publish',
735 input=case[0], expected=case[1],
736 id='%s[%r][%s]' % (dictname, name, casenum),
737 run_in_debugger=run_in_debugger,
738 # Passed to constructor of self.test_class:
739 writer_name=self.writer_name)
742 class HtmlPublishPartsTestSuite(CustomTestSuite):
744 def generateTests(self, dict, dictname='totest'):
745 for name, (settings_overrides, cases) in dict.items():
746 settings = self.suite_settings.copy()
747 settings.update(settings_overrides)
748 for casenum in range(len(cases)):
749 case = cases[casenum]
750 run_in_debugger = False
751 if len(case)==3:
752 if case[2]:
753 run_in_debugger = True
754 else:
755 continue
756 self.addTestCase(
757 HtmlWriterPublishPartsTestCase, 'test_publish',
758 input=case[0], expected=case[1],
759 id='%s[%r][%s]' % (dictname, name, casenum),
760 run_in_debugger=run_in_debugger,
761 suite_settings=settings)
764 class HtmlWriterPublishPartsTestCase(WriterPublishTestCase):
767 Test case for HTML writer via the publish_parts interface.
770 writer_name = 'html'
772 settings_default_overrides = \
773 WriterPublishTestCase.settings_default_overrides.copy()
774 settings_default_overrides['stylesheet'] = ''
776 def test_publish(self):
777 if self.run_in_debugger:
778 pdb.set_trace()
779 parts = docutils.core.publish_parts(
780 source=self.input,
781 reader_name='standalone',
782 parser_name='restructuredtext',
783 writer_name=self.writer_name,
784 settings_spec=self,
785 settings_overrides=self.suite_settings)
786 output = self.format_output(parts)
787 # interpolate standard variables:
788 expected = self.expected % {'version': docutils.__version__}
789 self.compare_output(self.input, output, expected)
791 standard_content_type_template = ('<meta http-equiv="Content-Type"'
792 ' content="text/html; charset=%s" />\n')
793 standard_generator_template = (
794 '<meta name="generator"'
795 ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
796 standard_html_meta_value = (
797 standard_content_type_template
798 + standard_generator_template % docutils.__version__)
799 standard_meta_value = standard_html_meta_value % 'utf-8'
800 standard_html_prolog = """\
801 <?xml version="1.0" encoding="%s" ?>
802 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
805 def format_output(self, parts):
806 """Minimize & standardize the output."""
807 # remove redundant parts & uninteresting parts:
808 del parts['whole']
809 assert parts['body'] == parts['fragment']
810 del parts['body']
811 del parts['body_pre_docinfo']
812 del parts['body_prefix']
813 del parts['body_suffix']
814 del parts['head']
815 del parts['head_prefix']
816 del parts['encoding']
817 del parts['version']
818 # remove standard portions:
819 parts['meta'] = parts['meta'].replace(self.standard_meta_value, '')
820 parts['html_head'] = parts['html_head'].replace(
821 self.standard_html_meta_value, '...')
822 parts['html_prolog'] = parts['html_prolog'].replace(
823 self.standard_html_prolog, '')
824 # remove empty values:
825 for key in parts.keys():
826 if not parts[key]:
827 del parts[key]
828 # standard output format:
829 keys = parts.keys()
830 keys.sort()
831 output = []
832 for key in keys:
833 output.append("%r: '''%s'''"
834 % (key, parts[key]))
835 if output[-1].endswith("\n'''"):
836 output[-1] = output[-1][:-4] + "\\n'''"
837 return '{' + ',\n '.join(output) + '}\n'
840 def exception_data(func, *args, **kwds):
842 Execute `func(*args, **kwds)` and return the resulting exception, the
843 exception arguments, and the formatted exception string.
845 try:
846 func(*args, **kwds)
847 except Exception, detail:
848 return (detail, detail.args,
849 '%s: %s' % (detail.__class__.__name__, detail))
852 def _format_str(*args):
853 r"""
854 Return a tuple containing representations of all args.
856 Same as map(repr, args) except that it returns multi-line
857 representations for strings containing newlines, e.g.::
859 '''\
860 foo \n\
863 baz'''
865 instead of::
867 'foo \nbar\n\nbaz'
869 This is a helper function for CustomTestCase.
871 return_tuple = []
872 for i in args:
873 r = repr(i)
874 if ( (isinstance(i, str) or isinstance(i, unicode))
875 and '\n' in i):
876 stripped = ''
877 if isinstance(i, unicode) and r.startswith('u'):
878 stripped = r[0]
879 r = r[1:]
880 elif isinstance(i, bytes) and r.startswith('b'):
881 stripped = r[0]
882 r = r[1:]
883 # quote_char = "'" or '"'
884 quote_char = r[0]
885 assert quote_char in ("'", '"'), quote_char
886 assert r[0] == r[-1]
887 r = r[1:-1]
888 r = (stripped + 3 * quote_char + '\\\n' +
889 re.sub(r'(?<!\\)((\\\\)*)\\n', r'\1\n', r) +
890 3 * quote_char)
891 r = re.sub(r' \n', r' \\n\\\n', r)
892 return_tuple.append(r)
893 return tuple(return_tuple)