diff options
-rw-r--r-- | CHANGES.txt | 3 | ||||
-rw-r--r-- | coverage/html.py | 43 | ||||
-rw-r--r-- | coverage/htmlfiles/index.html | 54 | ||||
-rw-r--r-- | coverage/htmlfiles/pyfile.html | 8 | ||||
-rw-r--r-- | coverage/htmlfiles/style.css | 48 |
5 files changed, 140 insertions, 16 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 988d9800..f3124137 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -7,7 +7,8 @@ Version 3.0b2 HTML reporting, and continued refactoring.
-- HTML reports and annotation of source files: use the new -b switch.
+- HTML reports and annotation of source files: use the new -b switch. THanks
+ to George Song for code, inspiration and guidance.
- Annotation into a directory (-a -d) behaves differently. The annotated files
are named with their hierarchy flattened so that same-named files from
diff --git a/coverage/html.py b/coverage/html.py index 41901b45..b88f89f1 100644 --- a/coverage/html.py +++ b/coverage/html.py @@ -25,6 +25,8 @@ class HtmlReporter(Reporter): self.directory = None self.source_tmpl = Templite(data("htmlfiles/pyfile.html"), globals()) + self.files = [] + def report(self, morfs, directory=None, omit_prefixes=None): assert directory, "must provide a directory for html reporting" @@ -45,6 +47,9 @@ class HtmlReporter(Reporter): # Process all the files. self.report_files(self.html_file, morfs, directory, omit_prefixes) + # Write the index file. + self.index_file() + def html_file(self, cu, statements, excluded, missing): """Generate an HTML file for one source file.""" @@ -57,7 +62,7 @@ class HtmlReporter(Reporter): n_mis = len(missing) n_run = n_stm - n_mis if n_stm > 0: - pc_cov = 100.0 * float(n_run) / n_stm + pc_cov = 100.0 * n_run / n_stm else: pc_cov = 100.0 @@ -88,12 +93,42 @@ class HtmlReporter(Reporter): } lines.append(lineinfo) - html_filename = os.path.join(self.directory, cu.flat_rootname()) - html_filename += ".html" - fhtml = open(html_filename, 'w') + # Write the HTML page for this file. + html_filename = cu.flat_rootname() + ".html" + html_path = os.path.join(self.directory, html_filename) + fhtml = open(html_path, 'w') fhtml.write(self.source_tmpl.render(locals())) fhtml.close() + # Save this file's information for the index file. + self.files.append({ + 'stm': n_stm, + 'run': n_run, + 'exc': n_exc, + 'mis': n_mis, + 'pc_cov': pc_cov, + 'html_filename': html_filename, + 'cu': cu, + }) + + def index_file(self): + """Write the index.html file for this report.""" + index_tmpl = Templite(data("htmlfiles/index.html"), globals()) + + files = self.files + + total_stm = sum([f['stm'] for f in files]) + total_run = sum([f['run'] for f in files]) + total_exc = sum([f['exc'] for f in files]) + if total_stm: + total_cov = 100.0 * total_run / total_stm + else: + total_cov = 100.0 + + fhtml = open(os.path.join(self.directory, "index.html"), "w") + fhtml.write(index_tmpl.render(locals())) + fhtml.close() + # Helpers for templates diff --git a/coverage/htmlfiles/index.html b/coverage/htmlfiles/index.html new file mode 100644 index 00000000..b6715c14 --- /dev/null +++ b/coverage/htmlfiles/index.html @@ -0,0 +1,54 @@ +<!doctype html PUBLIC "-//W3C//DTD html 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<title>Coverage report</title>
+<link rel='stylesheet' href='style.css' type='text/css'>
+</head>
+<body>
+
+<div id='header'>
+ <div class='content'>
+ <h1>Coverage report:
+ <span class='pc_cov'>{{total_cov|format_pct}}%</span>
+ </h1>
+ </div>
+</div>
+
+<div id='index'>
+<table class='index'>
+<tr>
+ <th class='name'>Module</th>
+ <th>statements</th>
+ <th>run</th>
+ <th>excluded</th>
+ <th>coverage</th>
+</tr>
+{% for file in files %}
+<tr>
+ <td class='name'><a href='{{file.html_filename}}'>{{file.cu.name}}</a></td>
+ <td>{{file.stm}}</td>
+ <td>{{file.run}}</td>
+ <td>{{file.exc}}</td>
+ <td>{{file.pc_cov|format_pct}}%</td>
+</tr>
+{% endfor %}
+<tr class='total'>
+<td class='name'>Total</td>
+<td>{{total_stm}}</td>
+<td>{{total_run}}</td>
+<td>{{total_exc}}</td>
+<td>{{total_cov|format_pct}}%</td>
+</tr>
+</table>
+</div>
+
+<div id='footer'>
+ <div class='content'>
+ <p>
+ <a class='nav' href='http://bitbucket.org/ned/coveragepy/'>coverage.py v{{__version__}}</a>
+ </p>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/coverage/htmlfiles/pyfile.html b/coverage/htmlfiles/pyfile.html index d4c15c6a..afcb4a5e 100644 --- a/coverage/htmlfiles/pyfile.html +++ b/coverage/htmlfiles/pyfile.html @@ -50,13 +50,5 @@ function toggle_lines(btn, cls) { </table>
</div>
-<div id='footer'>
- <div class='content'>
- <p>
- <a class='nav' href='http://bitbucket.org/ned/coveragepy/'>coverage.py v{{__version__}}</a>
- </p>
- </div>
-</div>
-
</body>
</html>
diff --git a/coverage/htmlfiles/style.css b/coverage/htmlfiles/style.css index 1a08b78e..5290bbd3 100644 --- a/coverage/htmlfiles/style.css +++ b/coverage/htmlfiles/style.css @@ -1,6 +1,6 @@ /* CSS styles for coverage.py */ /* Page-wide styles */ -html, body, h1, h2, h3, p, td { +html, body, h1, h2, h3, p, td, th { margin: 0; padding: 0; border: 0; @@ -14,6 +14,7 @@ html, body, h1, h2, h3, p, td { /* Set baseline grid to 16 pt. */ body { + font-family: georgia, serif; font-size: 1em; } @@ -27,6 +28,10 @@ p { line-height: 1.3333em; /* 16/12 */ } +table { + border-collapse: collapse; + } + a.nav { text-decoration: none; color: inherit; @@ -40,7 +45,6 @@ a.nav:hover { #header { background: #f8f8f8; width: 100%; - font-family: georgia, serif; border-bottom: 1px solid #eee; } @@ -56,9 +60,13 @@ a.nav:hover { font-style: italic; } +#index { + margin: 1em 0 0 3em; + } + /* Header styles */ .content { - padding: 1em 3em .5em 3em; + padding: 1em 3em; } h1 { @@ -115,3 +123,37 @@ td.text { .text p.hide { background: inherit; } + +/* index styles */ +#index td, #index th { + text-align: right; + width: 6em; + padding: .25em 0; + border-bottom: 1px solid #eee; + } +#index th { + font-style: italic; + color: #333; + border-bottom: 1px solid #ccc; + } +#index td.name, #index th.name { + text-align: left; + width: auto; + height: 1.5em; + } +#index td.name a { + text-decoration: none; + color: #000; + } +#index td.name a:hover { + text-decoration: underline; + color: #000; + } +#index tr.total { + font-weight: bold; + } +#index tr.total td { + padding: .25em 0; + border-top: 1px solid #ccc; + border-bottom: none; + } |