mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-02-22 02:16:42 +00:00
figleaf_htmlizer: expand tabs, fix to 4-space indents. No functional changes.
This commit is contained in:
parent
020715c8e7
commit
f3ed579e74
@ -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 > '
|
index_fp.write('<h2>Summary</h2> %d files total: %d files > '
|
||||||
'90%%, %d files > 75%%, %d files > 50%%<p>'
|
'90%%, %d files > 75%%, %d files > 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("&", "&")
|
s = s.replace("&", "&")
|
||||||
s = s.replace("<", "<")
|
s = s.replace("<", "<")
|
||||||
s = s.replace(">", ">")
|
s = s.replace(">", ">")
|
||||||
s = s.replace('"', """)
|
s = s.replace('"', """)
|
||||||
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)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user