DebugClients/Python3/coverage/xmlreport.py

changeset 29
391dc0bc4ae5
child 3495
fac17a82b431
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugClients/Python3/coverage/xmlreport.py	Thu Jan 07 13:13:31 2010 +0000
@@ -0,0 +1,146 @@
+"""XML reporting for coverage.py"""
+
+import os, sys, time
+import xml.dom.minidom
+
+from . import __url__, __version__
+from .backward import sorted            # pylint: disable-msg=W0622
+from .report import Reporter
+
+def rate(hit, num):
+    """Return the fraction of `hit`/`num`."""
+    return hit / (num or 1.0)
+
+
+class XmlReporter(Reporter):
+    """A reporter for writing Cobertura-style XML coverage results."""
+
+    def __init__(self, coverage, ignore_errors=False):
+        super(XmlReporter, self).__init__(coverage, ignore_errors)
+
+        self.packages = None
+        self.xml_out = None
+        self.arcs = coverage.data.has_arcs()
+
+    def report(self, morfs, omit_prefixes=None, outfile=None):
+        """Generate a Cobertura-compatible XML report for `morfs`.
+
+        `morfs` is a list of modules or filenames.  `omit_prefixes` is a list
+        of strings, prefixes of modules to omit from the report.
+
+        """
+        # Initial setup.
+        outfile = outfile or sys.stdout
+
+        # Create the DOM that will store the data.
+        impl = xml.dom.minidom.getDOMImplementation()
+        docType = impl.createDocumentType(
+            "coverage", None,
+            "http://cobertura.sourceforge.net/xml/coverage-03.dtd"
+            )
+        self.xml_out = impl.createDocument(None, "coverage", docType)
+
+        # Write header stuff.
+        xcoverage = self.xml_out.documentElement
+        xcoverage.setAttribute("version", __version__)
+        xcoverage.setAttribute("timestamp", str(int(time.time()*1000)))
+        xcoverage.appendChild(self.xml_out.createComment(
+            " Generated by coverage.py: %s " % __url__
+            ))
+        xpackages = self.xml_out.createElement("packages")
+        xcoverage.appendChild(xpackages)
+
+        # Call xml_file for each file in the data.
+        self.packages = {}
+        self.report_files(self.xml_file, morfs, omit_prefixes=omit_prefixes)
+
+        lnum_tot, lhits_tot = 0, 0
+        bnum_tot, bhits_tot = 0, 0
+
+        # Populate the XML DOM with the package info.
+        for pkg_name, pkg_data in self.packages.items():
+            class_elts, lhits, lnum, bhits, bnum = pkg_data
+            xpackage = self.xml_out.createElement("package")
+            xpackages.appendChild(xpackage)
+            xclasses = self.xml_out.createElement("classes")
+            xpackage.appendChild(xclasses)
+            for className in sorted(class_elts.keys()):
+                xclasses.appendChild(class_elts[className])
+            xpackage.setAttribute("name", pkg_name.replace(os.sep, '.'))
+            xpackage.setAttribute("line-rate", str(rate(lhits, lnum)))
+            xpackage.setAttribute("branch-rate", str(rate(bhits, bnum)))
+            xpackage.setAttribute("complexity", "0.0")
+
+            lnum_tot += lnum
+            lhits_tot += lhits
+            bnum_tot += bnum
+            bhits_tot += bhits
+
+        xcoverage.setAttribute("line-rate", str(rate(lhits_tot, lnum_tot)))
+        xcoverage.setAttribute("branch-rate", str(rate(bhits_tot, bnum_tot)))
+
+        # Use the DOM to write the output file.
+        outfile.write(self.xml_out.toprettyxml())
+
+    def xml_file(self, cu, analysis):
+        """Add to the XML report for a single file."""
+
+        # Create the 'lines' and 'package' XML elements, which
+        # are populated later.  Note that a package == a directory.
+        dirname, fname = os.path.split(cu.name)
+        dirname = dirname or '.'
+        package = self.packages.setdefault(dirname, [ {}, 0, 0, 0, 0 ])
+
+        xclass = self.xml_out.createElement("class")
+
+        xclass.appendChild(self.xml_out.createElement("methods"))
+
+        xlines = self.xml_out.createElement("lines")
+        xclass.appendChild(xlines)
+        className = fname.replace('.', '_')
+        xclass.setAttribute("name", className)
+        ext = os.path.splitext(cu.filename)[1]
+        xclass.setAttribute("filename", cu.name + ext)
+        xclass.setAttribute("complexity", "0.0")
+
+        branch_lines = analysis.branch_lines()
+
+        # For each statement, create an XML 'line' element.
+        for line in analysis.statements:
+            xline = self.xml_out.createElement("line")
+            xline.setAttribute("number", str(line))
+
+            # Q: can we get info about the number of times a statement is
+            # executed?  If so, that should be recorded here.
+            xline.setAttribute("hits", str(int(not line in analysis.missing)))
+
+            if self.arcs:
+                if line in branch_lines:
+                    xline.setAttribute("branch", "true")
+            xlines.appendChild(xline)
+
+        class_lines = 1.0 * len(analysis.statements)
+        class_hits = class_lines - len(analysis.missing)
+
+        if self.arcs:
+            # We assume here that every branch line has 2 exits, which is
+            # usually true.  In theory, though, we could have a branch line
+            # with more exits..
+            class_branches = 2.0 * len(branch_lines)
+            missed_branch_targets = analysis.missing_branch_arcs().values()
+            missing_branches = sum([len(b) for b in missed_branch_targets])
+            class_branch_hits = class_branches - missing_branches
+        else:
+            class_branches = 0.0
+            class_branch_hits = 0.0
+
+        # Finalize the statistics that are collected in the XML DOM.
+        line_rate = rate(class_hits, class_lines)
+        branch_rate = rate(class_branch_hits, class_branches)
+        xclass.setAttribute("line-rate", str(line_rate))
+        xclass.setAttribute("branch-rate", str(branch_rate))
+        package[0][className] = xclass
+        package[1] += class_hits
+        package[2] += class_lines
+        package[3] += class_branch_hits
+        package[4] += class_branches

eric ide

mercurial