figleaf_htmlizer: expand tabs, fix to 4-space indents. No functional changes.

This commit is contained in:
Brian Warner 2009-02-11 19:05:42 -07:00
parent 020715c8e7
commit f3ed579e74

View File

@ -12,269 +12,270 @@ logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('figleaf.htmlizer') logger = logging.getLogger('figleaf.htmlizer')
def read_exclude_patterns(f): def read_exclude_patterns(f):
if not f: if not f:
return [] return []
exclude_patterns = [] exclude_patterns = []
fp = open(f) fp = open(f)
for line in fp: for line in fp:
line = line.rstrip() line = line.rstrip()
if line and not line.startswith('#'): if line and not line.startswith('#'):
pattern = re.compile(line) pattern = re.compile(line)
exclude_patterns.append(pattern) exclude_patterns.append(pattern)
return exclude_patterns return exclude_patterns
def report_as_html(coverage, directory, exclude_patterns=[], root=None): def report_as_html(coverage, directory, exclude_patterns=[], root=None):
### now, output. ### now, output.
keys = coverage.keys() keys = coverage.keys()
info_dict = {} info_dict = {}
for k in keys: for k in keys:
skip = False skip = False
for pattern in exclude_patterns: for pattern in exclude_patterns:
if pattern.search(k): if pattern.search(k):
logger.debug('SKIPPING %s -- matches exclusion pattern' % k) logger.debug('SKIPPING %s -- matches exclusion pattern' % k)
skip = True skip = True
break break
if skip: if skip:
continue continue
if k.endswith('figleaf.py'): if k.endswith('figleaf.py'):
continue continue
display_filename = k display_filename = k
if root: if root:
if not k.startswith(root): if not k.startswith(root):
continue continue
display_filename = k[len(root):] display_filename = k[len(root):]
assert not display_filename.startswith("/") assert not display_filename.startswith("/")
assert display_filename.endswith(".py") assert display_filename.endswith(".py")
display_filename = display_filename[:-3] # trim .py display_filename = display_filename[:-3] # trim .py
display_filename = display_filename.replace("/", ".") display_filename = display_filename.replace("/", ".")
if not k.startswith("/"): if not k.startswith("/"):
continue continue
try: try:
pyfile = open(k) pyfile = open(k)
# print 'opened', k #print 'opened', k
except IOError: except IOError:
logger.warning('CANNOT OPEN: %s' % k) logger.warning('CANNOT OPEN: %s' % k)
continue continue
try: try:
lines = figleaf.get_lines(pyfile) lines = figleaf.get_lines(pyfile)
except KeyboardInterrupt: except KeyboardInterrupt:
raise raise
except Exception, e: except Exception, e:
pyfile.close() pyfile.close()
logger.warning('ERROR: %s %s' % (k, str(e))) logger.warning('ERROR: %s %s' % (k, str(e)))
continue continue
# ok, got all the info. now annotate file ==> html. # ok, got all the info. now annotate file ==> html.
covered = coverage[k] covered = coverage[k]
n_covered = n_lines = 0 n_covered = n_lines = 0
pyfile = open(k) pyfile = open(k)
output = [] output = []
for i, line in enumerate(pyfile): for i, line in enumerate(pyfile):
is_covered = False is_covered = False
is_line = False is_line = False
i += 1 i += 1
if i in covered: if i in covered:
is_covered = True is_covered = True
n_covered += 1 n_covered += 1
n_lines += 1 n_lines += 1
elif i in lines: elif i in lines:
is_line = True is_line = True
n_lines += 1 n_lines += 1
color = 'black' color = 'black'
if is_covered: if is_covered:
color = 'green' color = 'green'
elif is_line: elif is_line:
color = 'red' color = 'red'
line = escape_html(line.rstrip()) line = escape_html(line.rstrip())
output.append('<font color="%s">%4d. %s</font>' % (color, i, line.rstrip())) output.append('<font color="%s">%4d. %s</font>' % (color, i, line.rstrip()))
try: try:
pcnt = n_covered * 100. / n_lines pcnt = n_covered * 100. / n_lines
except ZeroDivisionError: except ZeroDivisionError:
pcnt = 0 pcnt = 0
info_dict[k] = (n_lines, n_covered, pcnt, display_filename) info_dict[k] = (n_lines, n_covered, pcnt, display_filename)
html_outfile = make_html_filename(display_filename) html_outfile = make_html_filename(display_filename)
html_outfp = open(os.path.join(directory, html_outfile), 'w') html_outfp = open(os.path.join(directory, html_outfile), 'w')
html_outfp.write('source file: <b>%s</b><br>\n' % (k,)) html_outfp.write('source file: <b>%s</b><br>\n' % (k,))
html_outfp.write('file stats: <b>%d lines, %d executed: %.1f%% covered</b>\n' % (n_lines, n_covered, pcnt)) html_outfp.write('file stats: <b>%d lines, %d executed: %.1f%% covered</b>\n' % (n_lines, n_covered, pcnt))
html_outfp.write('<pre>\n') html_outfp.write('<pre>\n')
html_outfp.write("\n".join(output)) html_outfp.write("\n".join(output))
html_outfp.close() html_outfp.close()
### print a summary, too. ### print a summary, too.
info_dict_items = info_dict.items() info_dict_items = info_dict.items()
def sort_by_pcnt(a, b): def sort_by_pcnt(a, b):
a = a[1][2] a = a[1][2]
b = b[1][2] b = b[1][2]
return -cmp(a,b) return -cmp(a,b)
def sort_by_uncovered(a, b): def sort_by_uncovered(a, b):
a_uncovered = a[1][0] - a[1][1] a_uncovered = a[1][0] - a[1][1]
b_uncovered = b[1][0] - b[1][1] b_uncovered = b[1][0] - b[1][1]
return -cmp(a_uncovered, b_uncovered) return -cmp(a_uncovered, b_uncovered)
info_dict_items.sort(sort_by_uncovered) info_dict_items.sort(sort_by_uncovered)
summary_lines = sum([ v[0] for (k, v) in info_dict_items]) 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_cover = sum([ v[1] for (k, v) in info_dict_items])
summary_pcnt = 0 summary_pcnt = 0
if summary_lines: if summary_lines:
summary_pcnt = float(summary_cover) * 100. / float(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] ] 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_90 = [ x for x in pcnts if x >= 90 ]
pcnt_75 = [ x for x in pcnts if x >= 75 ] pcnt_75 = [ x for x in pcnts if x >= 75 ]
pcnt_50 = [ x for x in pcnts if x >= 50 ] pcnt_50 = [ x for x in pcnts if x >= 50 ]
stats_fp = open('%s/stats.out' % (directory,), 'w') stats_fp = open('%s/stats.out' % (directory,), 'w')
stats_fp.write("total files: %d\n" % len(pcnts)) stats_fp.write("total files: %d\n" % len(pcnts))
stats_fp.write("total source lines: %d\n" % summary_lines) stats_fp.write("total source lines: %d\n" % summary_lines)
stats_fp.write("total covered lines: %d\n" % summary_cover) stats_fp.write("total covered lines: %d\n" % summary_cover)
stats_fp.write("total uncovered lines: %d\n" % stats_fp.write("total uncovered lines: %d\n" %
(summary_lines - summary_cover)) (summary_lines - summary_cover))
stats_fp.write("total coverage percentage: %.1f\n" % summary_pcnt) stats_fp.write("total coverage percentage: %.1f\n" % summary_pcnt)
stats_fp.close() stats_fp.close()
## index.html ## index.html
index_fp = open('%s/index.html' % (directory,), 'w') index_fp = open('%s/index.html' % (directory,), 'w')
# summary info # summary info
index_fp.write('<title>figleaf code coverage report</title>\n') index_fp.write('<title>figleaf code coverage report</title>\n')
index_fp.write('<h2>Summary</h2> %d files total: %d files &gt; ' index_fp.write('<h2>Summary</h2> %d files total: %d files &gt; '
'90%%, %d files &gt; 75%%, %d files &gt; 50%%<p>' '90%%, %d files &gt; 75%%, %d files &gt; 50%%<p>'
% (len(pcnts), len(pcnt_90), % (len(pcnts), len(pcnt_90),
len(pcnt_75), len(pcnt_50))) len(pcnt_75), len(pcnt_50)))
def emit_table(items, show_totals): def emit_table(items, show_totals):
index_fp.write('<table border=1><tr><th>Filename</th>' index_fp.write('<table border=1><tr><th>Filename</th>'
'<th># lines</th><th># covered</th>' '<th># lines</th><th># covered</th>'
'<th># uncovered</th>' '<th># uncovered</th>'
'<th>% covered</th></tr>\n') '<th>% covered</th></tr>\n')
if show_totals: if show_totals:
index_fp.write('<tr><td><b>totals:</b></td>' index_fp.write('<tr><td><b>totals:</b></td>'
'<td><b>%d</b></td>' '<td><b>%d</b></td>'
'<td><b>%d</b></td>' '<td><b>%d</b></td>'
'<td><b>%d</b></td>' '<td><b>%d</b></td>'
'<td><b>%.1f%%</b></td>' '<td><b>%.1f%%</b></td>'
'</tr>' '</tr>'
'<tr></tr>\n' '<tr></tr>\n'
% (summary_lines, summary_cover, % (summary_lines, summary_cover,
(summary_lines - summary_cover), (summary_lines - summary_cover),
summary_pcnt,)) summary_pcnt,))
for filename, stuff in items: for filename, stuff in items:
(n_lines, n_covered, percent_covered, display_filename) = stuff (n_lines, n_covered, percent_covered, display_filename) = stuff
html_outfile = make_html_filename(display_filename) html_outfile = make_html_filename(display_filename)
index_fp.write('<tr><td><a href="./%s">%s</a></td>' index_fp.write('<tr><td><a href="./%s">%s</a></td>'
'<td>%d</td><td>%d</td><td>%d</td><td>%.1f</td>' '<td>%d</td><td>%d</td><td>%d</td><td>%.1f</td>'
'</tr>\n' '</tr>\n'
% (html_outfile, display_filename, n_lines, % (html_outfile, display_filename, n_lines,
n_covered, (n_lines - n_covered), n_covered, (n_lines - n_covered),
percent_covered,)) percent_covered,))
index_fp.write('</table>\n') index_fp.write('</table>\n')
# sorted by number of lines that aren't covered # sorted by number of lines that aren't covered
index_fp.write('<h3>Sorted by Lines Uncovered</h3>\n') index_fp.write('<h3>Sorted by Lines Uncovered</h3>\n')
emit_table(info_dict_items, True) emit_table(info_dict_items, True)
# sorted by module name # sorted by module name
index_fp.write('<h3>Sorted by Module Name (alphabetical)</h3>\n') index_fp.write('<h3>Sorted by Module Name (alphabetical)</h3>\n')
info_dict_items.sort() info_dict_items.sort()
emit_table(info_dict_items, False) emit_table(info_dict_items, False)
index_fp.close() index_fp.close()
logger.info('reported on %d file(s) total\n' % len(info_dict)) logger.info('reported on %d file(s) total\n' % len(info_dict))
return len(info_dict) return len(info_dict)
def prepare_reportdir(dirname='html'): def prepare_reportdir(dirname='html'):
try: try:
os.mkdir(dirname) os.mkdir(dirname)
except OSError: # already exists except OSError: # already exists
pass pass
def make_html_filename(orig): def make_html_filename(orig):
return orig + ".html" return orig + ".html"
def escape_html(s): def escape_html(s):
s = s.replace("&", "&amp;") s = s.replace("&", "&amp;")
s = s.replace("<", "&lt;") s = s.replace("<", "&lt;")
s = s.replace(">", "&gt;") s = s.replace(">", "&gt;")
s = s.replace('"', "&quot;") s = s.replace('"', "&quot;")
return s return s
def main(): def main():
### ###
option_parser = OptionParser() option_parser = OptionParser()
option_parser.add_option('-x', '--exclude-patterns', action="store", option_parser.add_option('-x', '--exclude-patterns', action="store",
dest="exclude_patterns_file", dest="exclude_patterns_file",
help="file containing regexp patterns to exclude") help="file containing regexp patterns to exclude")
option_parser.add_option('-d', '--output-directory', action='store', option_parser.add_option('-d', '--output-directory', action='store',
dest="output_dir", dest="output_dir",
default = "html", default = "html",
help="directory for HTML output") help="directory for HTML output")
option_parser.add_option('-r', '--root', action="store", option_parser.add_option('-r', '--root', action="store",
dest="root", dest="root",
default=None, default=None,
help="only pay attention to modules under this directory") help="only pay attention to modules under this directory")
option_parser.add_option('-q', '--quiet', action='store_true', dest='quiet', help='Suppress all but error messages') option_parser.add_option('-q', '--quiet', action='store_true',
dest='quiet',
help='Suppress all but error messages')
(options, args) = option_parser.parse_args() (options, args) = option_parser.parse_args()
if options.quiet: if options.quiet:
logging.disable(logging.DEBUG) logging.disable(logging.DEBUG)
if options.root: if options.root:
options.root = os.path.abspath(options.root) options.root = os.path.abspath(options.root)
if options.root[-1] != "/": if options.root[-1] != "/":
options.root = options.root + "/" options.root = options.root + "/"
### load ### load
if not args: if not args:
args = ['.figleaf'] args = ['.figleaf']
coverage = {} coverage = {}
for filename in args: for filename in args:
logger.debug("loading coverage info from '%s'\n" % (filename,)) logger.debug("loading coverage info from '%s'\n" % (filename,))
d = figleaf.read_coverage(filename) d = figleaf.read_coverage(filename)
coverage = figleaf.combine_coverage(coverage, d) coverage = figleaf.combine_coverage(coverage, d)
if not coverage: if not coverage:
logger.warning('EXITING -- no coverage info!\n') logger.warning('EXITING -- no coverage info!\n')
sys.exit(-1) sys.exit(-1)
### make directory ### make directory
prepare_reportdir(options.output_dir) prepare_reportdir(options.output_dir)
report_as_html(coverage, options.output_dir, report_as_html(coverage, options.output_dir,
read_exclude_patterns(options.exclude_patterns_file), read_exclude_patterns(options.exclude_patterns_file),
options.root) options.root)