2 # Authors: David Goodger <goodger@python.org>;
3 # Garth Kidd <garth@deadlybloodyserious.com>
4 # Copyright: This module has been placed in the public domain.
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'
23 - `TransformTestSuite`
26 - `ParserTransformTestCase`
28 - `PEPParserTestSuite`
29 - `GridTableParserTestCase`
30 - `GridTableParserTestSuite`
31 - `SimpleTableParserTestCase`
32 - `SimpleTableParserTestSuite`
33 - `WriterPublishTestCase`
34 - `LatexWriterPublishTestCase`
35 - `PseudoXMLWriterPublishTestCase`
36 - `HtmlWriterPublishTestCase`
38 - `HtmlFragmentTestSuite`
39 - `DevNull` (output sink)
41 __docformat__
= 'reStructuredText'
49 from pprint
import pformat
51 testroot
= os
.path
.abspath(os
.path
.dirname(__file__
) or os
.curdir
)
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')))
59 import package_unittest
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
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
85 # Hack to make repr(StringList) look like repr(list):
86 StringList
.__repr
__ = StringList
.__str
__
93 def write(self
, string
):
100 class StandardTestCase(unittest
.TestCase
):
103 Helper class, providing the same interface as unittest.TestCase,
104 but with useful setUp and comparison methods.
110 def assertEqual(self
, first
, second
, msg
=None):
111 """Fail if the two objects are unequal as determined by the '=='
114 if not first
== second
:
115 raise self
.failureException
, \
116 (msg
or '%s != %s' % _format_str(first
, second
))
118 def assertNotEqual(self
, first
, second
, msg
=None):
119 """Fail if the two objects are equal as determined by the '=='
123 raise self
.failureException
, \
124 (msg
or '%s == %s' % _format_str(first
, second
))
127 if not hasattr(unittest
.TestCase
, "assertTrue"):
128 assertTrue
= unittest
.TestCase
.failUnless
130 # aliases for assertion methods, deprecated since Python 2.7
132 failUnlessEqual
= assertEquals
= assertEqual
134 assertNotEquals
= failIfEqual
= assertNotEqual
137 class CustomTestCase(StandardTestCase
):
140 Helper class, providing extended functionality over unittest.TestCase.
142 The methods assertEqual and assertNotEqual have been overwritten
143 to provide better support for multi-line strings. Furthermore,
144 see the compare_output method and the parameter list of __init__.
147 compare
= difflib
.Differ().compare
148 """Comparison method shared by all subclasses."""
150 def __init__(self
, method_name
, input, expected
, id,
151 run_in_debugger
=True, suite_settings
=None):
153 Initialise the CustomTestCase.
157 method_name -- name of test method to run.
158 input -- input to the parser.
159 expected -- expected output from the parser.
160 id -- unique test identifier, used by the test framework.
161 run_in_debugger -- if true, run this test under the pdb debugger.
162 suite_settings -- settings overrides for this test suite.
166 self
.expected
= expected
167 self
.run_in_debugger
= run_in_debugger
168 self
.suite_settings
= suite_settings
.copy() or {}
171 unittest
.TestCase
.__init
__(self
, method_name
)
175 Return string conversion. Overridden to give test id, in addition to
178 return '%s; %s' % (self
.id, unittest
.TestCase
.__str
__(self
))
181 return "<%s %s>" % (self
.id, unittest
.TestCase
.__repr
__(self
))
183 def clear_roles(self
):
184 # Language-specific roles and roles added by the
185 # "default-role" and "role" directives are currently stored
186 # globally in the roles._roles dictionary. This workaround
187 # empties that dictionary.
191 StandardTestCase
.setUp(self
)
194 def compare_output(self
, input, output
, expected
):
195 """`input`, `output`, and `expected` should all be strings."""
196 if isinstance(input, unicode):
197 input = input.encode('raw_unicode_escape')
198 if sys
.version_info
> (3,):
199 # API difference: Python 3's node.__str__ doesn't escape
200 #assert expected is None or isinstance(expected, unicode)
201 if isinstance(expected
, bytes
):
202 expected
= expected
.decode('utf-8')
203 if isinstance(output
, bytes
):
204 output
= output
.decode('utf-8')
206 if isinstance(expected
, unicode):
207 expected
= expected
.encode('raw_unicode_escape')
208 if isinstance(output
, unicode):
209 output
= output
.encode('raw_unicode_escape')
210 # Normalize line endings:
212 expected
= '\n'.join(expected
.splitlines())
214 output
= '\n'.join(output
.splitlines())
216 self
.assertEqual(output
, expected
)
217 except AssertionError, error
:
218 print >>sys
.stderr
, '\n%s\ninput:' % (self
,)
219 print >>sys
.stderr
, input
221 comparison
= ''.join(self
.compare(expected
.splitlines(1),
222 output
.splitlines(1)))
223 print >>sys
.stderr
, '-: expected\n+: output'
224 print >>sys
.stderr
, comparison
225 except AttributeError: # expected or output not a string
226 # alternative output for non-strings:
227 print >>sys
.stderr
, 'expected: %r' % expected
228 print >>sys
.stderr
, 'output: %r' % output
232 class CustomTestSuite(unittest
.TestSuite
):
235 A collection of CustomTestCases.
237 Provides test suite ID generation and a method for adding test cases.
241 """Identifier for the TestSuite. Prepended to the
242 TestCase identifiers to make identification easier."""
244 next_test_case_id
= 0
245 """The next identifier to use for non-identified test cases."""
247 def __init__(self
, tests
=(), id=None, suite_settings
=None):
249 Initialize the CustomTestSuite.
253 id -- identifier for the suite, prepended to test cases.
254 suite_settings -- settings overrides for this test suite.
256 unittest
.TestSuite
.__init
__(self
, tests
)
257 self
.suite_settings
= suite_settings
or {}
259 mypath
= os
.path
.abspath(
260 sys
.modules
[CustomTestSuite
.__module
__].__file
__)
261 outerframes
= inspect
.getouterframes(inspect
.currentframe())
262 for outerframe
in outerframes
[1:]:
263 if outerframe
[3] != '__init__':
264 callerpath
= outerframe
[1]
265 if callerpath
is None:
266 # It happens sometimes. Why is a mystery.
267 callerpath
= os
.getcwd()
268 callerpath
= os
.path
.abspath(callerpath
)
270 mydir
, myname
= os
.path
.split(mypath
)
273 if callerpath
.startswith(mydir
):
274 self
.id = callerpath
[len(mydir
) + 1:] # caller's module
280 def addTestCase(self
, test_case_class
, method_name
, input, expected
,
281 id=None, run_in_debugger
=False, **kwargs
):
283 Create a CustomTestCase in the CustomTestSuite.
284 Also return it, just in case.
288 test_case_class -- the CustomTestCase to add
289 method_name -- a string; CustomTestCase.method_name is the test
290 input -- input to the parser.
291 expected -- expected output from the parser.
292 id -- unique test identifier, used by the test framework.
293 run_in_debugger -- if true, run this test under the pdb debugger.
295 if id is None: # generate id if required
296 id = self
.next_test_case_id
297 self
.next_test_case_id
+= 1
298 # test identifier will become suiteid.testid
299 tcid
= '%s: %s' % (self
.id, id)
300 # suite_settings may be passed as a parameter;
301 # if not, set from attribute:
302 kwargs
.setdefault('suite_settings', self
.suite_settings
)
303 # generate and add test case
304 tc
= test_case_class(method_name
, input, expected
, tcid
,
305 run_in_debugger
=run_in_debugger
, **kwargs
)
309 def generate_no_tests(self
, *args
, **kwargs
):
313 class TransformTestCase(CustomTestCase
):
316 Output checker for the transform.
318 Should probably be called TransformOutputChecker, but I can deal with
319 that later when/if someone comes up with a category of transform test
320 cases that have nothing to do with the input and output of the transform.
323 option_parser
= frontend
.OptionParser(components
=(rst
.Parser
,))
324 settings
= option_parser
.get_default_values()
325 settings
.report_level
= 1
326 settings
.halt_level
= 5
327 settings
.debug
= package_unittest
.debug
328 settings
.warning_stream
= DevNull()
329 unknown_reference_resolvers
= ()
331 def __init__(self
, *args
, **kwargs
):
332 self
.transforms
= kwargs
['transforms']
333 """List of transforms to perform for this test case."""
335 self
.parser
= kwargs
['parser']
336 """Input parser for this test case."""
338 del kwargs
['transforms'], kwargs
['parser'] # only wanted here
339 CustomTestCase
.__init
__(self
, *args
, **kwargs
)
341 def supports(self
, format
):
344 def test_transforms(self
):
345 if self
.run_in_debugger
:
347 settings
= self
.settings
.copy()
348 settings
.__dict
__.update(self
.suite_settings
)
349 document
= utils
.new_document('test data', settings
)
350 self
.parser
.parse(self
.input, document
)
351 # Don't do a ``populate_from_components()`` because that would
352 # enable the Transformer's default transforms.
353 document
.transformer
.add_transforms(self
.transforms
)
354 document
.transformer
.add_transform(universal
.TestMessages
)
355 document
.transformer
.components
['writer'] = self
356 document
.transformer
.apply_transforms()
357 output
= document
.pformat()
358 self
.compare_output(self
.input, output
, self
.expected
)
360 def test_transforms_verbosely(self
):
361 if self
.run_in_debugger
:
366 settings
= self
.settings
.copy()
367 settings
.__dict
__.update(self
.suite_settings
)
368 document
= utils
.new_document('test data', settings
)
369 self
.parser
.parse(self
.input, document
)
371 print document
.pformat()
372 for transformClass
in self
.transforms
:
373 transformClass(document
).apply()
374 output
= document
.pformat()
377 self
.compare_output(self
.input, output
, self
.expected
)
380 class TransformTestSuite(CustomTestSuite
):
383 A collection of TransformTestCases.
385 A TransformTestSuite instance manufactures TransformTestCases,
386 keeps track of them, and provides a shared test fixture (a-la
390 def __init__(self
, parser
, suite_settings
=None):
392 """Parser shared by all test cases."""
394 CustomTestSuite
.__init
__(self
, suite_settings
=suite_settings
)
396 def generateTests(self
, dict, dictname
='totest',
397 testmethod
='test_transforms'):
399 Stock the suite with test cases generated from a test data dictionary.
401 Each dictionary key (test type's name) maps to a tuple, whose
402 first item is a list of transform classes and whose second
403 item is a list of tests. Each test is a list: input, expected
404 output, optional modifier. The optional third entry, a
405 behavior modifier, can be 0 (temporarily disable this test) or
406 1 (run this test under the pdb debugger). Tests should be
407 self-documenting and not require external comments.
409 for name
, (transforms
, cases
) in dict.items():
410 for casenum
in range(len(cases
)):
411 case
= cases
[casenum
]
412 run_in_debugger
= False
414 # TODO: (maybe) change the 3rd argument to a dict, so it
415 # can handle more cases by keyword ('disable', 'debug',
416 # 'settings'), here and in other generateTests methods.
417 # But there's also the method that
418 # HtmlPublishPartsTestSuite uses <DJG>
420 run_in_debugger
= True
424 TransformTestCase
, testmethod
,
425 transforms
=transforms
, parser
=self
.parser
,
426 input=case
[0], expected
=case
[1],
427 id='%s[%r][%s]' % (dictname
, name
, casenum
),
428 run_in_debugger
=run_in_debugger
)
431 class ParserTestCase(CustomTestCase
):
434 Output checker for the parser.
436 Should probably be called ParserOutputChecker, but I can deal with
437 that later when/if someone comes up with a category of parser test
438 cases that have nothing to do with the input and output of the parser.
441 parser
= rst
.Parser()
442 """Parser shared by all ParserTestCases."""
444 option_parser
= frontend
.OptionParser(components
=(rst
.Parser
,))
445 settings
= option_parser
.get_default_values()
446 settings
.report_level
= 5
447 settings
.halt_level
= 5
448 settings
.debug
= package_unittest
.debug
450 def test_parser(self
):
451 if self
.run_in_debugger
:
453 settings
= self
.settings
.copy()
454 settings
.__dict
__.update(self
.suite_settings
)
455 document
= utils
.new_document('test data', settings
)
456 self
.parser
.parse(self
.input, document
)
457 output
= document
.pformat()
458 self
.compare_output(self
.input, output
, self
.expected
)
461 class ParserTestSuite(CustomTestSuite
):
464 A collection of ParserTestCases.
466 A ParserTestSuite instance manufactures ParserTestCases,
467 keeps track of them, and provides a shared test fixture (a-la
471 test_case_class
= ParserTestCase
473 def generateTests(self
, dict, dictname
='totest'):
475 Stock the suite with test cases generated from a test data dictionary.
477 Each dictionary key (test type name) maps to a list of tests. Each
478 test is a list: input, expected output, optional modifier. The
479 optional third entry, a behavior modifier, can be 0 (temporarily
480 disable this test) or 1 (run this test under the pdb debugger). Tests
481 should be self-documenting and not require external comments.
483 for name
, cases
in dict.items():
484 for casenum
in range(len(cases
)):
485 case
= cases
[casenum
]
486 run_in_debugger
= False
489 run_in_debugger
= True
493 self
.test_case_class
, 'test_parser',
494 input=case
[0], expected
=case
[1],
495 id='%s[%r][%s]' % (dictname
, name
, casenum
),
496 run_in_debugger
=run_in_debugger
)
499 class PEPParserTestCase(ParserTestCase
):
501 """PEP-specific parser test case."""
503 parser
= rst
.Parser(rfc2822
=True, inliner
=rst
.states
.Inliner())
504 """Parser shared by all PEPParserTestCases."""
506 option_parser
= frontend
.OptionParser(components
=(rst
.Parser
, pep
.Reader
))
507 settings
= option_parser
.get_default_values()
508 settings
.report_level
= 5
509 settings
.halt_level
= 5
510 settings
.debug
= package_unittest
.debug
513 class PEPParserTestSuite(ParserTestSuite
):
515 """A collection of PEPParserTestCases."""
517 test_case_class
= PEPParserTestCase
520 class GridTableParserTestCase(CustomTestCase
):
522 parser
= tableparser
.GridTableParser()
524 def test_parse_table(self
):
525 self
.parser
.setup(StringList(string2lines(self
.input), 'test data'))
527 self
.parser
.find_head_body_sep()
528 self
.parser
.parse_table()
529 output
= self
.parser
.cells
530 except Exception, details
:
531 output
= '%s: %s' % (details
.__class
__.__name
__, details
)
532 self
.compare_output(self
.input, pformat(output
) + '\n',
533 pformat(self
.expected
) + '\n')
535 def test_parse(self
):
537 output
= self
.parser
.parse(StringList(string2lines(self
.input),
539 except Exception, details
:
540 output
= '%s: %s' % (details
.__class
__.__name
__, details
)
541 self
.compare_output(self
.input, pformat(output
) + '\n',
542 pformat(self
.expected
) + '\n')
545 class GridTableParserTestSuite(CustomTestSuite
):
548 A collection of GridTableParserTestCases.
550 A GridTableParserTestSuite instance manufactures GridTableParserTestCases,
551 keeps track of them, and provides a shared test fixture (a-la setUp and
555 test_case_class
= GridTableParserTestCase
557 def generateTests(self
, dict, dictname
='totest'):
559 Stock the suite with test cases generated from a test data dictionary.
561 Each dictionary key (test type name) maps to a list of tests. Each
562 test is a list: an input table, expected output from parse_table(),
563 expected output from parse(), optional modifier. The optional fourth
564 entry, a behavior modifier, can be 0 (temporarily disable this test)
565 or 1 (run this test under the pdb debugger). Tests should be
566 self-documenting and not require external comments.
568 for name
, cases
in dict.items():
569 for casenum
in range(len(cases
)):
570 case
= cases
[casenum
]
571 run_in_debugger
= False
574 run_in_debugger
= True
577 self
.addTestCase(self
.test_case_class
, 'test_parse_table',
578 input=case
[0], expected
=case
[1],
579 id='%s[%r][%s]' % (dictname
, name
, casenum
),
580 run_in_debugger
=run_in_debugger
)
581 self
.addTestCase(self
.test_case_class
, 'test_parse',
582 input=case
[0], expected
=case
[2],
583 id='%s[%r][%s]' % (dictname
, name
, casenum
),
584 run_in_debugger
=run_in_debugger
)
587 class SimpleTableParserTestCase(GridTableParserTestCase
):
589 parser
= tableparser
.SimpleTableParser()
592 class SimpleTableParserTestSuite(CustomTestSuite
):
595 A collection of SimpleTableParserTestCases.
598 test_case_class
= SimpleTableParserTestCase
600 def generateTests(self
, dict, dictname
='totest'):
602 Stock the suite with test cases generated from a test data dictionary.
604 Each dictionary key (test type name) maps to a list of tests. Each
605 test is a list: an input table, expected output from parse(), optional
606 modifier. The optional third entry, a behavior modifier, can be 0
607 (temporarily disable this test) or 1 (run this test under the pdb
608 debugger). Tests should be self-documenting and not require external
611 for name
, cases
in dict.items():
612 for casenum
in range(len(cases
)):
613 case
= cases
[casenum
]
614 run_in_debugger
= False
617 run_in_debugger
= True
620 self
.addTestCase(self
.test_case_class
, 'test_parse',
621 input=case
[0], expected
=case
[1],
622 id='%s[%r][%s]' % (dictname
, name
, casenum
),
623 run_in_debugger
=run_in_debugger
)
626 class PythonModuleParserTestCase(CustomTestCase
):
628 def test_parser(self
):
629 if self
.run_in_debugger
:
636 from docutils
.readers
.python
import moduleparser
637 module
= moduleparser
.parse_module(self
.input, 'test data').pformat()
639 self
.compare_output(self
.input, output
, self
.expected
)
641 def test_token_parser_rhs(self
):
642 if self
.run_in_debugger
:
649 from docutils
.readers
.python
import moduleparser
650 tr
= moduleparser
.TokenParser(self
.input)
652 self
.compare_output(self
.input, output
, self
.expected
)
655 class PythonModuleParserTestSuite(CustomTestSuite
):
658 A collection of PythonModuleParserTestCase.
661 def generateTests(self
, dict, dictname
='totest',
662 testmethod
='test_parser'):
664 Stock the suite with test cases generated from a test data dictionary.
666 Each dictionary key (test type's name) maps to a list of tests. Each
667 test is a list: input, expected output, optional modifier. The
668 optional third entry, a behavior modifier, can be 0 (temporarily
669 disable this test) or 1 (run this test under the pdb debugger). Tests
670 should be self-documenting and not require external comments.
672 for name
, cases
in dict.items():
673 for casenum
in range(len(cases
)):
674 case
= cases
[casenum
]
675 run_in_debugger
= False
678 run_in_debugger
= True
682 PythonModuleParserTestCase
, testmethod
,
683 input=case
[0], expected
=case
[1],
684 id='%s[%r][%s]' % (dictname
, name
, casenum
),
685 run_in_debugger
=run_in_debugger
)
688 class WriterPublishTestCase(CustomTestCase
, docutils
.SettingsSpec
):
691 Test case for publish.
694 settings_default_overrides
= {'_disable_config': 1,
696 writer_name
= '' # set in subclasses or constructor
698 def __init__(self
, *args
, **kwargs
):
699 if 'writer_name' in kwargs
:
700 self
.writer_name
= kwargs
['writer_name']
701 del kwargs
['writer_name']
702 CustomTestCase
.__init
__(self
, *args
, **kwargs
)
704 def test_publish(self
):
705 if self
.run_in_debugger
:
707 output
= docutils
.core
.publish_string(
709 reader_name
='standalone',
710 parser_name
='restructuredtext',
711 writer_name
=self
.writer_name
,
713 settings_overrides
=self
.suite_settings
)
714 self
.compare_output(self
.input, output
, self
.expected
)
717 class PublishTestSuite(CustomTestSuite
):
719 def __init__(self
, writer_name
, suite_settings
=None):
721 `writer_name` is the name of the writer to use.
723 CustomTestSuite
.__init
__(self
, suite_settings
=suite_settings
)
724 self
.test_class
= WriterPublishTestCase
725 self
.writer_name
= writer_name
727 def generateTests(self
, dict, dictname
='totest'):
728 for name
, cases
in dict.items():
729 for casenum
in range(len(cases
)):
730 case
= cases
[casenum
]
731 run_in_debugger
= False
734 run_in_debugger
= True
738 self
.test_class
, 'test_publish',
739 input=case
[0], expected
=case
[1],
740 id='%s[%r][%s]' % (dictname
, name
, casenum
),
741 run_in_debugger
=run_in_debugger
,
742 # Passed to constructor of self.test_class:
743 writer_name
=self
.writer_name
)
746 class HtmlPublishPartsTestSuite(CustomTestSuite
):
748 def generateTests(self
, dict, dictname
='totest'):
749 for name
, (settings_overrides
, cases
) in dict.items():
750 settings
= self
.suite_settings
.copy()
751 settings
.update(settings_overrides
)
752 for casenum
in range(len(cases
)):
753 case
= cases
[casenum
]
754 run_in_debugger
= False
757 run_in_debugger
= True
761 HtmlWriterPublishPartsTestCase
, 'test_publish',
762 input=case
[0], expected
=case
[1],
763 id='%s[%r][%s]' % (dictname
, name
, casenum
),
764 run_in_debugger
=run_in_debugger
,
765 suite_settings
=settings
)
768 class HtmlWriterPublishPartsTestCase(WriterPublishTestCase
):
771 Test case for HTML writer via the publish_parts interface.
776 settings_default_overrides
= \
777 WriterPublishTestCase
.settings_default_overrides
.copy()
778 settings_default_overrides
['stylesheet'] = ''
780 def test_publish(self
):
781 if self
.run_in_debugger
:
783 parts
= docutils
.core
.publish_parts(
785 reader_name
='standalone',
786 parser_name
='restructuredtext',
787 writer_name
=self
.writer_name
,
789 settings_overrides
=self
.suite_settings
)
790 output
= self
.format_output(parts
)
791 # interpolate standard variables:
792 expected
= self
.expected
% {'version': docutils
.__version
__}
793 self
.compare_output(self
.input, output
, expected
)
795 standard_content_type_template
= ('<meta http-equiv="Content-Type"'
796 ' content="text/html; charset=%s" />\n')
797 standard_generator_template
= (
798 '<meta name="generator"'
799 ' content="Docutils %s: http://docutils.sourceforge.net/" />\n')
800 standard_html_meta_value
= (
801 standard_content_type_template
802 + standard_generator_template
% docutils
.__version
__)
803 standard_meta_value
= standard_html_meta_value
% 'utf-8'
804 standard_html_prolog
= """\
805 <?xml version="1.0" encoding="%s" ?>
806 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
809 def format_output(self
, parts
):
810 """Minimize & standardize the output."""
811 # remove redundant parts & uninteresting parts:
813 assert parts
['body'] == parts
['fragment']
815 del parts
['body_pre_docinfo']
816 del parts
['body_prefix']
817 del parts
['body_suffix']
819 del parts
['head_prefix']
820 del parts
['encoding']
822 # remove standard portions:
823 parts
['meta'] = parts
['meta'].replace(self
.standard_meta_value
, '')
824 parts
['html_head'] = parts
['html_head'].replace(
825 self
.standard_html_meta_value
, '...')
826 parts
['html_prolog'] = parts
['html_prolog'].replace(
827 self
.standard_html_prolog
, '')
828 # remove empty values:
829 for key
in parts
.keys():
832 # standard output format:
837 output
.append("%r: '''%s'''"
839 if output
[-1].endswith("\n'''"):
840 output
[-1] = output
[-1][:-4] + "\\n'''"
841 return '{' + ',\n '.join(output
) + '}\n'
844 def exception_data(func
, *args
, **kwds
):
846 Execute `func(*args, **kwds)` and return the resulting exception, the
847 exception arguments, and the formatted exception string.
851 except Exception, detail
:
852 return (detail
, detail
.args
,
853 '%s: %s' % (detail
.__class
__.__name
__, detail
))
856 def _format_str(*args
):
858 Return a tuple containing representations of all args.
860 Same as map(repr, args) except that it returns multi-line
861 representations for strings containing newlines, e.g.::
873 This is a helper function for CustomTestCase.
878 if ( (isinstance(i
, str) or isinstance(i
, unicode))
881 if isinstance(i
, unicode) and r
.startswith('u'):
884 elif isinstance(i
, bytes
) and r
.startswith('b'):
887 # quote_char = "'" or '"'
889 assert quote_char
in ("'", '"'), quote_char
892 r
= (stripped
+ 3 * quote_char
+ '\\\n' +
893 re
.sub(r
'(?<!\\)((\\\\)*)\\n', r
'\1\n', r
) +
895 r
= re
.sub(r
' \n', r
' \\n\\\n', r
)
896 return_tuple
.append(r
)
897 return tuple(return_tuple
)