PK zb4%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;
}
PK xj4WOF F trace2htmldata/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 );
PK C8BA trace2htmldata/__init__.pyc;
SDc @ s d S( N( ( ( ( s; build/bdist.darwin-8.0.1-x86/egg/trace2htmldata/__init__.pys ? s PK C82 EGG-INFO/zip-safe
PK C8G 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
PK C82 EGG-INFO/dependency_links.txt
PK C8(E E EGG-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
PK C8r EGG-INFO/top_level.txttrace2htmldata
PK 99)8+zP P EGG-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
"""
#
# 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)
PK zb4%E% trace2htmldata/__init__.pyPK =j4*% N trace2htmldata/trace2html.cssPK xj4WOF F F trace2htmldata/sortabletable.jsPK C8BA qN trace2htmldata/__init__.pycPK C82 5O EGG-INFO/zip-safePK C8G 3@ @ eO EGG-INFO/SOURCES.txtPK C82 P EGG-INFO/dependency_links.txtPK C8(E E Q EGG-INFO/PKG-INFOPK C8r ` EGG-INFO/top_level.txtPK 99)8+zP P ` EGG-INFO/scripts/trace2html.pyPK