~jml/zope.testing/subunit-output-formatter

« back to all changes in this revision

Viewing changes to src/zope/testing/testrunner/formatter.py

  • Committer: Jonathan Lange
  • Date: 2010-03-11 20:05:37 UTC
  • Revision ID: jml@canonical.com-20100311200537-pjoajiu1nxfxca7k
Global imports

Show diffs side-by-side

added added

removed removed

Lines of Context:
664
664
        return self._id
665
665
 
666
666
 
 
667
# Conditional imports, we don't want zope.testing to have a hard dependency on
 
668
# subunit.
 
669
try:
 
670
    import subunit
 
671
    from subunit.iso8601 import Utc
 
672
except ImportError:
 
673
    subunit = None
 
674
 
 
675
 
 
676
# testtools is a hard dependency of subunit itself, guarding separately for
 
677
# richer error messages.
 
678
try:
 
679
    from testtools import content
 
680
except ImportError:
 
681
    content = None
 
682
 
 
683
 
667
684
class SubunitOutputFormatter(object):
668
685
    """A subunit output formatter.
669
686
 
699
716
    TAG_REFCOUNTS = 'zope:refcounts'
700
717
 
701
718
    def __init__(self, options):
702
 
        import subunit
703
 
        from subunit.iso8601 import Utc
 
719
        if subunit is None:
 
720
            raise Exception("Requires subunit 0.0.4 or better")
 
721
        if content is None:
 
722
            raise Exception("Requires testtools XXX or better")
704
723
        self.options = options
705
724
        self._stream = sys.stdout
706
725
        self._subunit = subunit.TestProtocolClient(self._stream)
708
727
        # None or (layer_name, last_touched_time).
709
728
        self._last_layer = None
710
729
        self.UTC = Utc()
 
730
        # Content types used in the output.
 
731
        self.TRACEBACK_CONTENT_TYPE = content.ContentType(
 
732
            'text', 'x-traceback', dict(language='python', charset='utf8'))
 
733
        self.PROFILE_CONTENT_TYPE = content.ContentType(
 
734
            'application', 'x-binary-profile')
 
735
        self.PLAIN_TEXT = content.ContentType(
 
736
            'text', 'plain', {'charset': 'utf8'})
711
737
 
712
738
    def _emit_tag(self, tag):
713
739
        self._stream.write('tags: %s\n' % (tag,))
873
899
        # from testtools. However, 'OutputFormatter' contains special logic to
874
900
        # handle errors from doctests, so we have to use that and manually
875
901
        # create an object equivalent to an instance of 'TracebackContent'.
876
 
        from testtools.content import Content, ContentType
877
 
        content_type = ContentType(
878
 
            'text', 'x-traceback', dict(language='python', charset='utf8'))
879
902
        formatter = OutputFormatter(None)
880
903
        traceback = formatter.format_traceback(exc_info)
881
904
        return {
882
 
            'traceback': Content(
883
 
                content_type, lambda: [traceback.encode('utf8')])}
 
905
            'traceback': content.Content(
 
906
                self.TRACEBACK_CONTENT_TYPE, lambda: [traceback.encode('utf8')])}
884
907
 
885
908
    def test_error(self, test, seconds, exc_info):
886
909
        """Report that an error occurred while running a test.
904
927
 
905
928
    def profiler_stats(self, stats):
906
929
        """Report profiler stats."""
907
 
        from testtools import content
908
930
        # XXX: <lifeless> jml: for the mime type, you can pick one from the
909
931
        # IANA, or make one up according to the RFC rules on making them up.
910
932
        # -- jml
911
 
        profile_type = content.ContentType('application', 'x-binary-profile')
912
933
        ignored, filename = tempfile.mkstemp()
913
934
        try:
914
935
            stats.dump_stats(filename)
915
 
            content = content.Content(profile_type, open(filename).read)
916
 
            details = {'profiler-stats': content}
 
936
            profile_content = content.Content(
 
937
                self.PROFILE_CONTENT_TYPE, open(filename).read)
 
938
            details = {'profiler-stats': profile_content}
917
939
        finally:
918
940
            os.unlink(filename)
919
941
        # Name the test 'zope:profiler_stats' just like its tag.
954
976
 
955
977
    def _get_text_details(self, name, text):
956
978
        """Get a details dictionary that just has some plain text."""
957
 
        from testtools import content
958
 
        plain_text = content.ContentType('text', 'plain', {'charset': 'utf8'})
959
979
        return {
960
 
            name: content.Content(plain_text, lambda: [text.encode('utf8')])}
 
980
            name: content.Content(
 
981
                self.PLAIN_TEXT, lambda: [text.encode('utf8')])}
961
982
 
962
983
    def garbage(self, garbage):
963
984
        """Report garbage generated by tests."""