diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-13 18:31:26 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-09-13 18:31:26 -0400 |
commit | 45a968fd8cce233722108df0aec10ef019a873de (patch) | |
tree | 08df6c6494bfc5441c19e662d096cde909742ac4 /coverage/xmlreport.py | |
parent | 02c9a25ecd0762cdb26c0c6ac9e817f6e92ccc43 (diff) | |
download | python-coveragepy-45a968fd8cce233722108df0aec10ef019a873de.tar.gz |
XML reporting hooked up, but not everything is right: a test_farm test fails now??
Diffstat (limited to 'coverage/xmlreport.py')
-rw-r--r-- | coverage/xmlreport.py | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/coverage/xmlreport.py b/coverage/xmlreport.py new file mode 100644 index 0000000..82d06f6 --- /dev/null +++ b/coverage/xmlreport.py @@ -0,0 +1,117 @@ +"""XML reporting for coverage.py""" + +import os, sys +import xml.dom.minidom + +from coverage.report import Reporter + + +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) + + 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 + self.find_code_units(morfs, omit_prefixes) + + # 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" ) + doc = impl.createDocument(None, "coverage", docType) + root = doc.documentElement + + packageXml = doc.createElement("packages") + root.appendChild(packageXml) + packages = {} + + errors = False + for cu in self.code_units: + # 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 = packages.setdefault( + dirname, [ doc.createElement("package"), {}, 0, 0, 0, 0 ] ) + c = doc.createElement("class") + lines = doc.createElement("lines") + c.appendChild(lines) + className = fname.replace('.', '_') + c.setAttribute("name", className) + c.setAttribute("filename", cu.name) + c.setAttribute("complexity", "0.0") + + try: + statements, _, missing, _ = self.coverage._analyze(cu) + + # For each statement, create an XML 'line' element. + for line in statements: + l = doc.createElement("line") + l.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. + if not line in missing: + l.setAttribute("hits", str(1)) + + # Q: can we get info about whether this statement + # is a branch? If so, that data should be + # used here. + l.setAttribute("branch", "false") + lines.appendChild(l) + class_lines = 1.0 * len(statements) + class_hits = class_lines - len(missing) + class_branches = 0.0 + class_branch_hits = 0.0 + + # Finalize the statistics that are collected in the XML DOM. + line_rate = class_hits / (class_lines or 1.0) + branch_rate = class_branch_hits / (class_branches or 1.0) + c.setAttribute("line-rate", str(line_rate)) + c.setAttribute("branch-rate", str(branch_rate)) + package[1][className] = c + package[2] += class_hits + package[3] += class_lines + package[4] += class_branch_hits + package[5] += class_branches + except KeyboardInterrupt: #pragma: no cover + raise + except: + if not self.ignore_errors: + typ, msg = sys.exc_info()[:2] + fmt_err = "%s %s: %s\n" + outfile.write(fmt_err % (cu.name, typ.__name__, msg)) + errors = True + + # Don't write the XML data if we've encountered errors. + if errors: + return + + # Populate the XML DOM with the package info. + for packageName, packageData in packages.items(): + package = packageData[0] + packageXml.appendChild(package) + classes = doc.createElement("classes") + package.appendChild(classes) + classNames = packageData[1].keys() + classNames.sort() + for className in classNames: + classes.appendChild(packageData[1][className]) + package.setAttribute("name", packageName.replace(os.sep, '.')) + package.setAttribute("line-rate", str(packageData[2]/(packageData[3] or 1.0))) + package.setAttribute("branch-rate", str(packageData[4] / (packageData[5] or 1.0) )) + package.setAttribute("complexity", "0.0") + + # Use the DOM to write the output file. + outfile.write(doc.toprettyxml()) |