PKzb4%E%trace2htmldata/__init__.py# make this a package PK=j4*%trace2htmldata/trace2html.css/** * Default CSS style for the trace2html utility by Olivier Grisel * This stylesheet is public domain content. */ /* Common style */ body { font-family: Lucida Grande, Verdana, Arial, Helvetica, sans-serif; font-size: 90%; color: #222; margin: 1.5em; } h1 { font-weight: bold; font-size: 100%; color: #444; border-bottom: 1px solid #f70; } p.footer { font-size: 80%; font-style: italic; } a, a:visited { font-weight: bold; text-decoration: none; color: #335; } a:hover { color: #339; text-decoration: underline; } table { border: 1px solid #ddd; background-color: #ddd; width: 100%; margin: 0.5em; font-size: 90%; } table tr { background-color: white; } table thead td, table tbody tr.odd { background-color: #eee; } table thead td { text-align: center; font-weight: bold; font-size: 100%; } table td { padding: 0.05em 0.5em 0.05em 0.5em; } /* General modules index and coverage summary */ table.summary { border-spacing: 1px; } table.summary td.percent { width: 16em; } table.summary div.coveragePercent { float: left; width: 5em; text-align: right; } table.summary div.coverageBar { background-color: #f22; margin: 0.2em; width: 10em; float: left; border: 1px solid #444; } table.summary div.coverageBar div.inCoverageBar { background-color: #2f2; height: 1em; } /* Annotated source file */ table.srcCode { border-spacing: 0px; } table.srcCode pre { margin: 0 } table.srcCode tr { background-color: white; } table.srcCode tr.uncovered { background-color: #f44; font-weight: bold; } table.srcCode td.nbLine, table.srcCode td.nbHits { text-align: right; border-right: 1px solid #ddd; width: 3em; } PKxj4WOFFtrace2htmldata/sortabletable.js /*----------------------------------------------------------------------------\ | Sortable Table 1.12 | |-----------------------------------------------------------------------------| | Created by Erik Arvidsson | | (http://webfx.eae.net/contact.html#erik) | | For WebFX (http://webfx.eae.net/) | |-----------------------------------------------------------------------------| | A DOM 1 based script that allows an ordinary HTML table to be sortable. | |-----------------------------------------------------------------------------| | Copyright (c) 1998 - 2004 Erik Arvidsson | |-----------------------------------------------------------------------------| | This software is provided "as is", without warranty of any kind, express or | | implied, including but not limited to the warranties of merchantability, | | fitness for a particular purpose and noninfringement. In no event shall the | | authors or copyright holders be liable for any claim, damages or other | | liability, whether in an action of contract, tort or otherwise, arising | | from, out of or in connection with the software or the use or other | | dealings in the software. | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | This software is available under the three different licenses mentioned | | below. To use this software you must chose, and qualify, for one of those. | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | The WebFX Non-Commercial License http://webfx.eae.net/license.html | | Permits anyone the right to use the software in a non-commercial context | | free of charge. | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | The WebFX Commercial license http://webfx.eae.net/commercial.html | | Permits the license holder the right to use the software in a commercial | | context. Such license must be specifically obtained, however it's valid for | | any number of implementations of the licensed software. | | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | | GPL - The GNU General Public License http://www.gnu.org/licenses/gpl.txt | | Permits anyone the right to use and modify the software without limitations | | as long as proper credits are given and the original and modified source | | code are included. Requires that the final product, software derivate from | | the original source or any software utilizing a GPL component, such as | | this, is also licensed under the GPL license. | |-----------------------------------------------------------------------------| | 2003-01-10 | First version | | 2003-01-19 | Minor changes to the date parsing | | 2003-01-28 | JScript 5.0 fixes (no support for 'in' operator) | | 2003-02-01 | Sloppy typo like error fixed in getInnerText | | 2003-07-04 | Added workaround for IE cellIndex bug. | | 2003-11-09 | The bDescending argument to sort was not correctly working | | | Using onclick DOM0 event if no support for addEventListener | | | or attachEvent | | 2004-01-13 | Adding addSortType and removeSortType which makes it a lot | | | easier to add new, custom sort types. | | 2004-01-27 | Switch to use descending = false as the default sort order. | | | Change defaultDescending to suit your needs. | | 2004-03-14 | Improved sort type None look and feel a bit | | 2004-08-26 | Made the handling of tBody and tHead more flexible. Now you | | | can use another tHead or no tHead, and you can chose some | | | other tBody. | |-----------------------------------------------------------------------------| | Created 2003-01-10 | All changes are in the log above. | Updated 2004-08-26 | \----------------------------------------------------------------------------*/ function SortableTable(oTable, oSortTypes) { this.sortTypes = oSortTypes || []; this.sortColumn = null; this.descending = null; var oThis = this; this._headerOnclick = function (e) { oThis.headerOnclick(e); }; if (oTable) { this.setTable( oTable ); this.document = oTable.ownerDocument || oTable.document; } else { this.document = document; } // only IE needs this var win = this.document.defaultView || this.document.parentWindow; this._onunload = function () { oThis.destroy(); }; if (win && typeof win.attachEvent != "undefined") { win.attachEvent("onunload", this._onunload); } } SortableTable.gecko = navigator.product == "Gecko"; SortableTable.msie = /msie/i.test(navigator.userAgent); // Mozilla is faster when doing the DOM manipulations on // an orphaned element. MSIE is not SortableTable.removeBeforeSort = SortableTable.gecko; SortableTable.prototype.onsort = function () {}; // default sort order. true -> descending, false -> ascending SortableTable.prototype.defaultDescending = false; // shared between all instances. This is intentional to allow external files // to modify the prototype SortableTable.prototype._sortTypeInfo = {}; SortableTable.prototype.setTable = function (oTable) { if ( this.tHead ) this.uninitHeader(); this.element = oTable; this.setTHead( oTable.tHead ); this.setTBody( oTable.tBodies[0] ); }; SortableTable.prototype.setTHead = function (oTHead) { if (this.tHead && this.tHead != oTHead ) this.uninitHeader(); this.tHead = oTHead; this.initHeader( this.sortTypes ); }; SortableTable.prototype.setTBody = function (oTBody) { this.tBody = oTBody; }; SortableTable.prototype.setSortTypes = function ( oSortTypes ) { if ( this.tHead ) this.uninitHeader(); this.sortTypes = oSortTypes || []; if ( this.tHead ) this.initHeader( this.sortTypes ); }; // adds arrow containers and events // also binds sort type to the header cells so that reordering columns does // not break the sort types SortableTable.prototype.initHeader = function (oSortTypes) { if (!this.tHead) return; var cells = this.tHead.rows[0].cells; var doc = this.tHead.ownerDocument || this.tHead.document; this.sortTypes = oSortTypes || []; var l = cells.length; var img, c; for (var i = 0; i < l; i++) { c = cells[i]; if (this.sortTypes[i] != null && this.sortTypes[i] != "None") { img = doc.createElement("IMG"); img.src = "images/blank.png"; c.appendChild(img); if (this.sortTypes[i] != null) c._sortType = this.sortTypes[i]; if (typeof c.addEventListener != "undefined") c.addEventListener("click", this._headerOnclick, false); else if (typeof c.attachEvent != "undefined") c.attachEvent("onclick", this._headerOnclick); else c.onclick = this._headerOnclick; } else { c.setAttribute( "_sortType", oSortTypes[i] ); c._sortType = "None"; } } this.updateHeaderArrows(); }; // remove arrows and events SortableTable.prototype.uninitHeader = function () { if (!this.tHead) return; var cells = this.tHead.rows[0].cells; var l = cells.length; var c; for (var i = 0; i < l; i++) { c = cells[i]; if (c._sortType != null && c._sortType != "None") { c.removeChild(c.lastChild); if (typeof c.removeEventListener != "undefined") c.removeEventListener("click", this._headerOnclick, false); else if (typeof c.detachEvent != "undefined") c.detachEvent("onclick", this._headerOnclick); c._sortType = null; c.removeAttribute( "_sortType" ); } } }; SortableTable.prototype.updateHeaderArrows = function () { if (!this.tHead) return; var cells = this.tHead.rows[0].cells; var l = cells.length; var img; for (var i = 0; i < l; i++) { if (cells[i]._sortType != null && cells[i]._sortType != "None") { img = cells[i].lastChild; if (i == this.sortColumn) img.className = "sort-arrow " + (this.descending ? "descending" : "ascending"); else img.className = "sort-arrow"; } } }; SortableTable.prototype.headerOnclick = function (e) { // find TD element var el = e.target || e.srcElement; while (el.tagName != "TD") el = el.parentNode; this.sort(SortableTable.msie ? SortableTable.getCellIndex(el) : el.cellIndex); }; // IE returns wrong cellIndex when columns are hidden SortableTable.getCellIndex = function (oTd) { var cells = oTd.parentNode.childNodes var l = cells.length; var i; for (i = 0; cells[i] != oTd && i < l; i++) ; return i; }; SortableTable.prototype.getSortType = function (nColumn) { return this.sortTypes[nColumn] || "String"; }; // only nColumn is required // if bDescending is left out the old value is taken into account // if sSortType is left out the sort type is found from the sortTypes array SortableTable.prototype.sort = function (nColumn, bDescending, sSortType) { if (!this.tBody) return; if (sSortType == null) sSortType = this.getSortType(nColumn); // exit if None if (sSortType == "None") return; if (bDescending == null) { if (this.sortColumn != nColumn) this.descending = this.defaultDescending; else this.descending = !this.descending; } else this.descending = bDescending; this.sortColumn = nColumn; if (typeof this.onbeforesort == "function") this.onbeforesort(); var f = this.getSortFunction(sSortType, nColumn); var a = this.getCache(sSortType, nColumn); var tBody = this.tBody; a.sort(f); if (this.descending) a.reverse(); if (SortableTable.removeBeforeSort) { // remove from doc var nextSibling = tBody.nextSibling; var p = tBody.parentNode; p.removeChild(tBody); } // insert in the new order var l = a.length; for (var i = 0; i < l; i++) tBody.appendChild(a[i].element); if (SortableTable.removeBeforeSort) { // insert into doc p.insertBefore(tBody, nextSibling); } this.updateHeaderArrows(); this.destroyCache(a); if (typeof this.onsort == "function") this.onsort(); }; SortableTable.prototype.asyncSort = function (nColumn, bDescending, sSortType) { var oThis = this; this._asyncsort = function () { oThis.sort(nColumn, bDescending, sSortType); }; window.setTimeout(this._asyncsort, 1); }; SortableTable.prototype.getCache = function (sType, nColumn) { if (!this.tBody) return []; var rows = this.tBody.rows; var l = rows.length; var a = new Array(l); var r; for (var i = 0; i < l; i++) { r = rows[i]; a[i] = { value: this.getRowValue(r, sType, nColumn), element: r }; }; return a; }; SortableTable.prototype.destroyCache = function (oArray) { var l = oArray.length; for (var i = 0; i < l; i++) { oArray[i].value = null; oArray[i].element = null; oArray[i] = null; } }; SortableTable.prototype.getRowValue = function (oRow, sType, nColumn) { // if we have defined a custom getRowValue use that if (this._sortTypeInfo[sType] && this._sortTypeInfo[sType].getRowValue) return this._sortTypeInfo[sType].getRowValue(oRow, nColumn); var s; var c = oRow.cells[nColumn]; if (typeof c.innerText != "undefined") s = c.innerText; else s = SortableTable.getInnerText(c); return this.getValueFromString(s, sType); }; SortableTable.getInnerText = function (oNode) { var s = ""; var cs = oNode.childNodes; var l = cs.length; for (var i = 0; i < l; i++) { switch (cs[i].nodeType) { case 1: //ELEMENT_NODE s += SortableTable.getInnerText(cs[i]); break; case 3: //TEXT_NODE s += cs[i].nodeValue; break; } } return s; }; SortableTable.prototype.getValueFromString = function (sText, sType) { if (this._sortTypeInfo[sType]) return this._sortTypeInfo[sType].getValueFromString( sText ); return sText; /* switch (sType) { case "Number": return Number(sText); case "CaseInsensitiveString": return sText.toUpperCase(); case "Date": var parts = sText.split("-"); var d = new Date(0); d.setFullYear(parts[0]); d.setDate(parts[2]); d.setMonth(parts[1] - 1); return d.valueOf(); } return sText; */ }; SortableTable.prototype.getSortFunction = function (sType, nColumn) { if (this._sortTypeInfo[sType]) return this._sortTypeInfo[sType].compare; return SortableTable.basicCompare; }; SortableTable.prototype.destroy = function () { this.uninitHeader(); var win = this.document.parentWindow; if (win && typeof win.detachEvent != "undefined") { // only IE needs this win.detachEvent("onunload", this._onunload); } this._onunload = null; this.element = null; this.tHead = null; this.tBody = null; this.document = null; this._headerOnclick = null; this.sortTypes = null; this._asyncsort = null; this.onsort = null; }; // Adds a sort type to all instance of SortableTable // sType : String - the identifier of the sort type // fGetValueFromString : function ( s : string ) : T - A function that takes a // string and casts it to a desired format. If left out the string is just // returned // fCompareFunction : function ( n1 : T, n2 : T ) : Number - A normal JS sort // compare function. Takes two values and compares them. If left out less than, // <, compare is used // fGetRowValue : function( oRow : HTMLTRElement, nColumn : int ) : T - A function // that takes the row and the column index and returns the value used to compare. // If left out then the innerText is first taken for the cell and then the // fGetValueFromString is used to convert that string the desired value and type SortableTable.prototype.addSortType = function (sType, fGetValueFromString, fCompareFunction, fGetRowValue) { this._sortTypeInfo[sType] = { type: sType, getValueFromString: fGetValueFromString || SortableTable.idFunction, compare: fCompareFunction || SortableTable.basicCompare, getRowValue: fGetRowValue }; }; // this removes the sort type from all instances of SortableTable SortableTable.prototype.removeSortType = function (sType) { delete this._sortTypeInfo[sType]; }; SortableTable.basicCompare = function compare(n1, n2) { if (n1.value < n2.value) return -1; if (n2.value < n1.value) return 1; return 0; }; SortableTable.idFunction = function (x) { return x; }; SortableTable.toUpperCase = function (s) { return s.toUpperCase(); }; SortableTable.toDate = function (s) { var parts = s.split("-"); var d = new Date(0); d.setFullYear(parts[0]); d.setDate(parts[2]); d.setMonth(parts[1] - 1); return d.valueOf(); }; // add sort types SortableTable.prototype.addSortType("Number", Number); SortableTable.prototype.addSortType("CaseInsensitiveString", SortableTable.toUpperCase); SortableTable.prototype.addSortType("Date", SortableTable.toDate); SortableTable.prototype.addSortType("String"); // None is a special case /* --- Appending code from the Cobertura project --- */ /* * Cobertura - http://cobertura.sourceforge.net/ * * Copyright (C) 2005 Mark Doliner * Copyright (C) 2005 Olivier Parent * * Cobertura is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * Cobertura is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cobertura; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ function percentageSortType( s ) { var ret; var i = s.indexOf( "%" ); if (i != -1) { s = s.substr( 0, i ); } ret = parseFloat(s); if (isNaN(ret)) { ret = -1; } return ret; } SortableTable.prototype.addSortType( "Percentage", percentageSortType ); // This is needed for correctly sorting numbers in different // locales. The stock number converter only expects to sort // numbers which use a period as a separator instead of a // comma (like French). function formattedNumberSortType( s ) { var ret; var i = s.indexOf(';'); if (i != -1) { s = s.substring(0, i); } ret = parseFloat(s); if (isNaN(ret)) { return -1; } return ret; } SortableTable.prototype.addSortType( "FormattedNumber", formattedNumberSortType ); PKC8BA trace2htmldata/__init__.pyc; SDc@sdS(N((((s;build/bdist.darwin-8.0.1-x86/egg/trace2htmldata/__init__.pys?sPKC82EGG-INFO/zip-safe PKC8G 3@@EGG-INFO/SOURCES.txtCOPYING.txt MANIFEST.in NEWS.txt README.txt ez_setup.py setup.py src/trace2html.py src/trace2htmldata/__init__.py src/trace2htmldata/sortabletable.js src/trace2htmldata/trace2html.css trace2html.egg-info/PKG-INFO trace2html.egg-info/SOURCES.txt trace2html.egg-info/dependency_links.txt trace2html.egg-info/top_level.txt PKC82EGG-INFO/dependency_links.txt PKC8(EEEGG-INFO/PKG-INFOMetadata-Version: 1.0 Name: trace2html Version: 0.2.1 Summary: HTML coverage report generator for trace.py Home-page: http://champiland.homelinux.net/trace2html Author: Olivier Grisel Author-email: olivier.grisel@ensta.org License: GNU GPL v2 Description: trace2html ========== :author: Olivier Grisel `trace2html` is a utility to convert execution coverage data obtained with the `trace` module of the standard python library into a set of human readable HTML documents showing sortable summary and annotated source files. Installation ------------ As usual, you can either use `sudo easy_install -U trace2html` or extract the archive and run:: $ sudo python setup.py install Sample usage ------------ Use trace2html to directly compute the coverage of a test suite by specifying the module you are interested in:: $ trace2html.py -w my_module --run-command ./my_testrunner.py $ firefox coverage_dir/index.html Or you can collect coverage data generated with trace.py:: $ /usr/lib/python2.4/trace.py -mc -C coverage_dir -f counts my_testrunner.py Write a report in directory 'other_dir' from data collected in 'counts':: $ trace2html.py -f counts -o other_dir $ firefox other_dir/index.html Use the `--help` option for more details. Licensing --------- `trace2html` is released under the GNU/GPL v2 license (see COPYING.txt for more details) and uses the I would not mind relicensing `trace2html` under a more liberal license such as the Python or ZPL licenses but that would only be useful if someone find or write a replacement for the WebFX Sortable Table JS file under a similar license. SortableTable.js is currently under GPLv2. Bug reports and patches ----------------------- You can directly send bug reports and patches to my personnal email address:: olivier.grisel@ensta.org Or you can use `bzr`__ to branch my repository:: $ bzr branch http://champiland.homelinux.net/trace2html/code/trace2html.og.main trace2html.me.main then publish your branch on some site and send me a merge request. Please follow the `5-minute tutorial`__ if you are new to bzr. Credits ------- `trace2html` is inspired by the `cobertura project`__ for java programs. It includes Javascript code from WebFX Sortable Table and Cobertura. .. References __`bzr`:: http://bazaar-vcs.org/ __`5-minute tutorial`:: http://bazaar-vcs.org/QuickHackingWithBzr __`cobertura project`:: http://cobertura.sourceforge.net Changelog ========= 0.2.1 ----- - packaging bugfixes (added missing files in the source distribution) (thanks to Grig Gheorghiu for the bug reports) 0.2.0 ----- - trace2html.py can now be directly used to collect coverage data - new whitelist system to explicitely restrict the traced modules 0.1.1 ----- - minor bugfix in options help message 0.1.0 ----- - initial revision Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python PKC8rEGG-INFO/top_level.txttrace2htmldata PK99)8 +zPPEGG-INFO/scripts/trace2html.py#!/usr/local/bin/python2.3 # (C) Copyright 2006 Olivier Grisel # Author: Olivier Grisel # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # $Id$ """trace2html.py [options] Utility to generate HTML test coverage reports for python programs Example usage ------------- Use trace2html to directly compute the coverage of a test suite by specifying the module you are interested in:: $ trace2html.py -w my_module --run-command ./my_testrunner.py $ firefox coverage_dir/index.html Or you can collect coverage data generated with trace.py:: $ /usr/lib/python2.4/trace.py -mc -C coverage_dir -f counts my_testrunner.py Write a report in directory 'other_dir' from data collected in 'counts':: $ trace2html.py -f counts -o other_dir $ firefox other_dir/index.html """ import cgi import datetime import linecache import optparse import os import sys import trace import urllib try: # Extracted resources from the trace2html data even if it's packaged as # an egg from pkg_resources import resource_string TRACE2HTML_CSS = resource_string('trace2htmldata', 'trace2html.css') SORTABLETABLE_JS = resource_string('trace2htmldata', 'sortabletable.js') except ImportError: # distutils backward compatibility import trace2htmldata resources = trace2htmldata.__path__[0] TRACE2HTML_CSS = file(os.path.join(resources, 'trace2html.css')).read() SORTABLETABLE_JS = file(os.path.join(resources, 'sortabletable.js')).read() # # First some HTML templates # HTML_PAGE = """\ %(title)s

%(title)s

%(body)s """ SUMMARY = """\ %(summary_lines)s
ModuleCoverage %%
""" SUMMARY_LINE = """\ %(modulename)s
%(percent)d%%
""" ANNOTATED_SOURCE_FILE = """\ %(summary)s %(src_lines)s
""" ANNOTATED_SOURCE_LINE = """\ %(line_number)s %(line_hits)s %(src_line)s """ # # Command line options parsing # def parse_args(args): """Use optparse to extract options from the argv list >>> args = '--coverage-file=/tmp/some_file -f another_file'.split() >>> options, _ = parse_args(args) >>> options.coverage_files ['/tmp/some_file', 'another_file'] >>> options.report_dir 'coverage_dir' >>> args = '-f another_file -o /tmp/report'.split() >>> options, _ = parse_args(args) >>> options.coverage_files ['another_file'] >>> options.report_dir '/tmp/report' """ parser = optparse.OptionParser(usage=__doc__) parser.add_option('-f', '--coverage-file', action='append', dest='coverage_files', default=[], help="Use the content of a trace file") parser.add_option('-o', '--output-dir', action='store', dest='report_dir', default='coverage_dir', help="Directory to store the generated HTML report. " "Defaults to 'coverage_dir'") # TODO: use it! parser.add_option('-s', '--with-css-stylesheet', action='store', dest='css', default=None, help="Use an alternative CSS stylesheet") parser.add_option('-t', '--self-test', action='store_true', dest='selftest', default=False, help="Run the tests for trace2html") parser.add_option('-v', '--verbose', action='count', default=0, help="Set verbose mode on (cumulative)") parser.add_option('-r', '--run-command', action='store_true', dest='run_command', default=False, help="Collect coverage data by running the given " "python script with all trailing arguments") parser.add_option('-b', '--blacklist-module', action='append', dest='blacklist_mods', default=[], help="Add a module to the black list") parser.add_option('-B', '--blacklist-dir', action='append', dest='blacklist_dirs', default=[], help="Add a directory to the black list") parser.add_option('-w', '--whitelist-module', action='append', dest='whitelist_mods', default=[], help="Add a module to the white list") parser.add_option('-W', '--whitelist-dir', action='append', dest='whitelist_dirs', default=[], help="Add a directory to the white list") return parser.parse_args(args=args) # # Then comes the logic # def _strip_init(modulename): """Utility function to clean badly guessed module names:: >>> _strip_init('my_package.__init__') 'my_package' >>> _strip_init('os.path') 'os.path' """ if modulename.endswith('.__init__'): modulename = modulename[:-len('.__init__')] return modulename # First a patch for trace.Trace.globaltrace_lt: this will be applied directly # on a trace.Trace instance if needed to help it deal with packages if True: def globaltrace_lt(self, frame, why, arg): """Handler for call events. If the code block being entered is to be ignored, returns `None', else returns self.localtrace. """ if why == 'call': code = frame.f_code filename = code.co_filename if filename: # XXX: OG - use fullname instead of simple modname to better # deal with packages #modulename = modname(filename) modulename = _strip_init(trace.fullmodname(filename)) if modulename is not None: ignore_it = self.ignore.names(filename, modulename) if not ignore_it: if self.trace: print (" --- modulename: %s, funcname: %s" % (modulename, code.co_name)) return self.localtrace else: return None class Handle(object): """Implement the same interface as trace.Ignore but do the opposite The list of modules of dirs given as arguments of the constructor are a whitelist of modules to be traced. Files that do not belong to one of those list are ignores (the `names` method will return 1 as for trace.Ignore.names):: >>> handle = Handle(modules=['os']) >>> handle.names(os.__file__, 'os') 0 >>> handle.names(trace.__file__, 'trace') 1 Handle can reuse an existing trace.Ignore instance and delegate the final choice by delegation to further refine the selection:: >>> ignore = trace.Ignore(modules=['os.path']) >>> handle2 = Handle(modules=['os'], ignore=ignore) >>> handle2.names(os.__file__, 'os') 0 >>> handle2.names(os.path.__file__, 'os.path') 1 Some special cases are always the ignored, such as string code:: >>> handle.names('foo', '') 1 >>> handle2.names('foo', '') 1 And builtins:: >>> handle.names(None, '__builtins__') 1 >>> handle2.names(None, '__builtins__') 1 """ def __init__(self, modules=None, dirs=None, ignore=None): # internally use a trace.Ignore instance to reuse the existing logics # but will inverse it in the names implementation self._handle = trace.Ignore(modules=modules, dirs=dirs) # update the '' case however self._handle._ignore[''] = 0 # store the ignore instance (if any) that will be used in the regular # way to further refine the decision self._ignore = ignore def names(self, filename, modulename): """Ask the _handle trace.Ignore instance but volontary mis-interpret it's reply """ modulename = _strip_init(modulename) if self._handle.names(filename, modulename): # it's probably a submodule except if filename is None if filename is None: # must be a built-in, so we must ignore it anyway return 1 # filename/modulename is a submodule of the whitelist if self._ignore is not None: # further refine with the ignore instance return self._ignore.names(filename, modulename) else: # accept it directly return 0 # else it's not a submodule, thus ignore it return 1 class CoverageHtmlResults(trace.CoverageResults): """Extend the coverage results class to add the ability to compute coverage summary data and write it down as html reports """ _page_pattern = HTML_PAGE _summary_pattern = SUMMARY _summary_line_pattern = SUMMARY_LINE _annotated_src_file_pattern = ANNOTATED_SOURCE_FILE _annotated_src_line_pattern = ANNOTATED_SOURCE_LINE _default_css_filename = 'trace2html.css' _default_js_filename = 'sortabletable.js' def writeHtmlReport(self, report_dir, css_filename=None): """Write the report of the collected data to report_dir after creating it if not existing This is highly 'inspirated' by how trace.CoverageResults writes it's reports. >>> import tempfile, shutil, os >>> report_dir = tempfile.mkdtemp() >>> reporter = CoverageHtmlResults() >>> reporter.writeHtmlReport(report_dir) # doctest: +ELLIPSIS '...index.html' >>> os.listdir(report_dir) ['trace2html.css', 'sortabletable.js', 'index.html'] Cleaning the test directory:: >>> shutil.rmtree(report_dir) """ # write the directory if not os.path.exists(report_dir): os.mkdir(report_dir) # write the css file if css_filename is not None: css_data = file(css_filename).read() else: css_filename = self._default_css_filename css_data = TRACE2HTML_CSS file(os.path.join(report_dir, css_filename), 'w').write(css_data) # write the js file for summary lines sorting js_filename = self._default_js_filename js_data = SORTABLETABLE_JS file(os.path.join(report_dir, js_filename), 'w').write(js_data) # turn the counts data ("(filename, lineno) = count") into something # accessible on a per-file basis per_file_counts = {} for (filename, lineno), count in self.counts.iteritems(): lines_hit = per_file_counts.setdefault(filename, {}) lines_hit[lineno] = count # accumulate summary info sums = {} for filename, count in per_file_counts.iteritems(): # skip some "files" we don't care about... if filename == "": continue if filename.endswith(".pyc") or filename.endswith(".pyo"): filename = filename[:-1] # Get a list of the line numbers which represent executable content # (returned as a dict for better lookup speed) lnotab = trace.find_executable_linenos(filename) source = linecache.getlines(filename) modulename = trace.fullmodname(filename) modulename = _strip_init(modulename) percent = self._writeAnnotatedSourceCodePage( report_dir, modulename, source, lnotab, count, css_filename) sums[modulename] = percent # write the summary index_filename = os.path.join(report_dir, 'index.html') self._writePage(index_filename, 'Coverage Report - All Modules', self._summary(sums), css_filename) return os.path.abspath(index_filename) def _writeAnnotatedSourceCodePage(self, report_dir, modulename, lines, lnotab, lines_hit, css_filename=None): """Write an annotated html version of the source code of the module This is highly inspirated by the CoverageResults.write_results_file method. """ filename = os.path.join(report_dir, modulename + ".html") # counters for the summary n_hits, n_lines = 0, 0 annotated_lines = '' for i, line in enumerate(lines): lineno = i + 1 if line.strip(): src_line = '
%s
' % cgi.escape(line[:-1]) else: src_line = '' params = { 'coverage_class': '', 'line_number': str(lineno), 'line_hits': '', 'src_line': src_line, } # do the blank/comment match to try to mark more lines # (help the reader find stuff that hasn't been covered) if lineno in lines_hit: params['line_hits'] = str(lines_hit[lineno]) n_hits += 1 n_lines += 1 elif not trace.rx_blank.match(line): # lines preceded by no marks weren't hit # Highlight them if so indicated, unless the line contains # #pragma: NO COVER if lineno in lnotab and not trace.PRAGMA_NOCOVER in lines[i]: n_lines += 1 params['line_hits'] = '0' params['coverage_class'] = 'uncovered' annotated_lines += ANNOTATED_SOURCE_LINE % params if not n_lines: n_lines, n_hits = 1, 1 percent = int(100 * n_hits / n_lines) summary = self._summary({modulename: percent}) body = ANNOTATED_SOURCE_FILE % { 'module_path': modulename, 'summary': summary, 'src_lines': annotated_lines, } title = "Coverage Report - %s" % modulename self._writePage(filename, title, body, css_filename) return percent def _summary(self, stats): summary_lines = '' for i, (modulename, percent) in enumerate(sorted(stats.iteritems())): summary_lines += SUMMARY_LINE % { 'modulename': cgi.escape(modulename), 'module_link': urllib.quote(modulename + '.html'), 'percent': percent, 'row_class': i % 2 is 0 and 'even' or 'odd', } return SUMMARY % {'summary_lines': summary_lines} def _writePage(self, filename, title, body, css_filename=None): """Generate an html page a write it to filename""" data = { 'title': title, 'body': body, 'css_file': css_filename or self._default_css_filename, 'date': str(datetime.datetime.now()), } file(filename, 'w').write(self._page_pattern % data) def main(original_args): #pragma: NO COVER """Write a report according to the collected options""" # split args between trace2html options and the testrunner options cmd_args = [] args = original_args[:] if '--run-command' in sys.argv: i = args.index('--run-command') + 1 args, cmd_args = original_args[:i], original_args[i:] if '-r' in args: i = args.index('-r') + 1 args, cmd_args = args[:i], args[i:] + cmd_args # parse args that are specific to trace2html options, remaining_args = parse_args(args[1:]) if remaining_args: print "unrecognised argument %r, please use --help for instructions" % ( remaining_args[0]) sys.exit(1) # self testing if options.selftest: # returns the number of failures as return code sys.exit(_test(options.verbose)[0]) if not options.coverage_files and not options.run_command: # avoid writing a report for nothing if options.verbose: print "no data to collect: please use --help for instructions" sys.exit(0) reporter = CoverageHtmlResults() for coverage_file in options.coverage_files: # collecting coverage data from count files if options.verbose: print "collecting coverage data for %s..." % coverage_file reporter.update(trace.CoverageResults(infile=coverage_file)) if options.run_command and cmd_args: # collecting coverage data from a live trace if options.verbose: print "collecting coverage data for %r..." % ' '.join(cmd_args) sys.argv = cmd_args progname = cmd_args[0] sys.path[0] = os.path.split(progname)[0] # build a tracer with black and white lists logics if options.blacklist_dirs or options.blacklist_mods: bl_dirs = map(os.path.abspath, options.blacklist_dirs) ignore = trace.Ignore(dirs=bl_dirs, modules=options.blacklist_mods) else: ignore = None if options.whitelist_dirs or options.whitelist_mods: wl_dirs = map(os.path.abspath, options.whitelist_dirs) handle = Handle(dirs=wl_dirs, modules=options.whitelist_mods, ignore=ignore) else: handle = ignore t = trace.Trace(count=1, trace=0) # apply our patch to better handle packages t.globaltrace = lambda x,y,z: globaltrace_lt(t, x, y, z) if handle: # use our black/whitelist system instead of the simple ignore list # that comes by default t.ignore = handle # run the tracer try: t.run('execfile(%r)' % (progname,)) except IOError, err: print >> sys.stderr, "cannot run file %r because: %s" % ( sys.argv[0], err) sys.exit(1) except SystemExit: pass reporter.update(t.results()) # writing the report try: report_path = reporter.writeHtmlReport(options.report_dir, options.css) print "report written to: %s" % report_path except IOError, err: print >> sys.stderr, "could not write the report, cause: %s" % err sys.exit(1) # # selftest support # def _test(verbose=0): import doctest return doctest.testmod(verbose=verbose) def test_suite(): """setuptools testrunner integration""" import trace2html, doctest return doctest.DocTestSuite(trace2html) # Run away! if __name__ == "__main__": #pragma: NO COVER main(sys.argv) PKzb4%E%trace2htmldata/__init__.pyPK=j4*%Ntrace2htmldata/trace2html.cssPKxj4WOFFFtrace2htmldata/sortabletable.jsPKC8BA qNtrace2htmldata/__init__.pycPKC825OEGG-INFO/zip-safePKC8G 3@@eOEGG-INFO/SOURCES.txtPKC82PEGG-INFO/dependency_links.txtPKC8(EEQEGG-INFO/PKG-INFOPKC8r`EGG-INFO/top_level.txtPK99)8 +zPP`EGG-INFO/scripts/trace2html.pyPK