#! /usr/bin/env python
import sys
import figleaf
import os
import re
from optparse import OptionParser
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('figleaf.htmlizer')
def read_exclude_patterns(f):
if not f:
return []
exclude_patterns = []
fp = open(f)
for line in fp:
line = line.rstrip()
if line and not line.startswith('#'):
pattern = re.compile(line)
exclude_patterns.append(pattern)
return exclude_patterns
def report_as_html(coverage, directory, exclude_patterns=[], root=None):
### now, output.
keys = coverage.keys()
info_dict = {}
for k in keys:
skip = False
for pattern in exclude_patterns:
if pattern.search(k):
logger.debug('SKIPPING %s -- matches exclusion pattern' % k)
skip = True
break
if skip:
continue
if k.endswith('figleaf.py'):
continue
display_filename = k
if root:
if not k.startswith(root):
continue
display_filename = k[len(root):]
assert not display_filename.startswith("/")
assert display_filename.endswith(".py")
display_filename = display_filename[:-3] # trim .py
display_filename = display_filename.replace("/", ".")
if not k.startswith("/"):
continue
try:
pyfile = open(k)
#print 'opened', k
except IOError:
logger.warning('CANNOT OPEN: %s' % k)
continue
try:
lines = figleaf.get_lines(pyfile)
except KeyboardInterrupt:
raise
except Exception, e:
pyfile.close()
logger.warning('ERROR: %s %s' % (k, str(e)))
continue
# ok, got all the info. now annotate file ==> html.
covered = coverage[k]
n_covered = n_lines = 0
pyfile = open(k)
output = []
for i, line in enumerate(pyfile):
is_covered = False
is_line = False
i += 1
if i in covered:
is_covered = True
n_covered += 1
n_lines += 1
elif i in lines:
is_line = True
n_lines += 1
color = 'black'
if is_covered:
color = 'green'
elif is_line:
color = 'red'
line = escape_html(line.rstrip())
output.append('%4d. %s' % (color, i, line.rstrip()))
try:
pcnt = n_covered * 100. / n_lines
except ZeroDivisionError:
pcnt = 0
info_dict[k] = (n_lines, n_covered, pcnt, display_filename)
html_outfile = make_html_filename(display_filename)
html_outfp = open(os.path.join(directory, html_outfile), 'w')
html_outfp.write('source file: %s
\n' % (k,))
html_outfp.write('file stats: %d lines, %d executed: %.1f%% covered\n' % (n_lines, n_covered, pcnt))
html_outfp.write('
\n') html_outfp.write("\n".join(output)) html_outfp.close() ### print a summary, too. info_dict_items = info_dict.items() def sort_by_pcnt(a, b): a = a[1][2] b = b[1][2] return -cmp(a,b) def sort_by_uncovered(a, b): a_uncovered = a[1][0] - a[1][1] b_uncovered = b[1][0] - b[1][1] return -cmp(a_uncovered, b_uncovered) info_dict_items.sort(sort_by_uncovered) summary_lines = sum([ v[0] for (k, v) in info_dict_items]) summary_cover = sum([ v[1] for (k, v) in info_dict_items]) summary_pcnt = 0 if summary_lines: summary_pcnt = float(summary_cover) * 100. / float(summary_lines) pcnts = [ float(v[1]) * 100. / float(v[0]) for (k, v) in info_dict_items if v[0] ] pcnt_90 = [ x for x in pcnts if x >= 90 ] pcnt_75 = [ x for x in pcnts if x >= 75 ] pcnt_50 = [ x for x in pcnts if x >= 50 ] stats_fp = open('%s/stats.out' % (directory,), 'w') stats_fp.write("total files: %d\n" % len(pcnts)) stats_fp.write("total source lines: %d\n" % summary_lines) stats_fp.write("total covered lines: %d\n" % summary_cover) stats_fp.write("total uncovered lines: %d\n" % (summary_lines - summary_cover)) stats_fp.write("total coverage percentage: %.1f\n" % summary_pcnt) stats_fp.close() ## index.html index_fp = open('%s/index.html' % (directory,), 'w') # summary info index_fp.write('figleaf code coverage report \n') index_fp.write('Summary
%d files total: %d files > ' '90%%, %d files > 75%%, %d files > 50%%' % (len(pcnts), len(pcnt_90), len(pcnt_75), len(pcnt_50))) def emit_table(items, show_totals): index_fp.write('
Filename | ' '# lines | # covered | ' '# uncovered | ' '% covered |
---|---|---|---|---|
totals: | ' '%d | ' '%d | ' '%d | ' '%.1f%% | ' '
%s | ' '%d | %d | %d | %.1f | ' '