summaryrefslogtreecommitdiff
path: root/coverage/html.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2011-04-10 08:42:31 -0400
committerNed Batchelder <ned@nedbatchelder.com>2011-04-10 08:42:31 -0400
commit52e07c90b77b1d07ed95a6195ec5d895f0988224 (patch)
tree325346a20aedac88b3297919f5c1c89f79de7aed /coverage/html.py
parentd4dd809d27ad7f31431a4ef61309b6951ad41d9b (diff)
parent822b7c82f58bbd6f2b38cc98c7881cc405d0c69e (diff)
downloadpython-coveragepy-52e07c90b77b1d07ed95a6195ec5d895f0988224.tar.gz
Merge Brett's __main__.py file for the tree.
Diffstat (limited to 'coverage/html.py')
-rw-r--r--coverage/html.py147
1 files changed, 135 insertions, 12 deletions
diff --git a/coverage/html.py b/coverage/html.py
index 87edad4..802327d 100644
--- a/coverage/html.py
+++ b/coverage/html.py
@@ -2,8 +2,9 @@
import os, re, shutil
-from coverage import __url__, __version__ # pylint: disable=W0611
-from coverage.misc import CoverageException
+import coverage
+from coverage.backward import pickle
+from coverage.misc import CoverageException, Hasher
from coverage.phystokens import source_token_lines
from coverage.report import Reporter
from coverage.templite import Templite
@@ -32,18 +33,29 @@ class HtmlReporter(Reporter):
STATIC_FILES = [
"style.css",
"jquery-1.4.3.min.js",
- "jquery.tablesorter.min.js",
"jquery.hotkeys.js",
+ "jquery.isonscreen.js",
+ "jquery.tablesorter.min.js",
"coverage_html.js",
]
- def __init__(self, coverage, ignore_errors=False):
- super(HtmlReporter, self).__init__(coverage, ignore_errors)
+ def __init__(self, cov, ignore_errors=False):
+ super(HtmlReporter, self).__init__(cov, ignore_errors)
self.directory = None
- self.source_tmpl = Templite(data("htmlfiles/pyfile.html"), globals())
+ self.template_globals = {
+ 'escape': escape,
+ '__url__': coverage.__url__,
+ '__version__': coverage.__version__,
+ }
+ self.source_tmpl = Templite(
+ data("htmlfiles/pyfile.html"), self.template_globals
+ )
+
+ self.coverage = cov
self.files = []
- self.arcs = coverage.data.has_arcs()
+ self.arcs = self.coverage.data.has_arcs()
+ self.status = HtmlStatus()
def report(self, morfs, config=None):
"""Generate an HTML report for `morfs`.
@@ -54,6 +66,17 @@ class HtmlReporter(Reporter):
"""
assert config.html_dir, "must provide a directory for html reporting"
+ # Read the status data.
+ self.status.read(config.html_dir)
+
+ # Check that this run used the same settings as the last run.
+ m = Hasher()
+ m.update(config)
+ these_settings = m.digest()
+ if self.status.settings_hash() != these_settings:
+ self.status.reset()
+ self.status.set_settings_hash(these_settings)
+
# Process all the files.
self.report_files(self.html_file, morfs, config, config.html_dir)
@@ -70,6 +93,13 @@ class HtmlReporter(Reporter):
os.path.join(self.directory, static)
)
+ def file_hash(self, source, cu):
+ """Compute a hash that changes if the file needs to be re-reported."""
+ m = Hasher()
+ m.update(source)
+ self.coverage.data.add_to_hash(cu.filename, m)
+ return m.digest()
+
def html_file(self, cu, analysis):
"""Generate an HTML file for one source file."""
source_file = cu.source_file()
@@ -78,6 +108,17 @@ class HtmlReporter(Reporter):
finally:
source_file.close()
+ # Find out if the file on disk is already correct.
+ flat_rootname = cu.flat_rootname()
+ this_hash = self.file_hash(source, cu)
+ that_hash = self.status.file_hash(flat_rootname)
+ if this_hash == that_hash:
+ # Nothing has changed to require the file to be reported again.
+ self.files.append(self.status.index_info(flat_rootname))
+ return
+
+ self.status.set_file_hash(flat_rootname, this_hash)
+
nums = analysis.numbers
missing_branch_arcs = analysis.missing_branch_arcs()
@@ -141,7 +182,7 @@ class HtmlReporter(Reporter):
})
# Write the HTML page for this file.
- html_filename = cu.flat_rootname() + ".html"
+ html_filename = flat_rootname + ".html"
html_path = os.path.join(self.directory, html_filename)
html = spaceless(self.source_tmpl.render(locals()))
fhtml = open(html_path, 'w')
@@ -151,16 +192,20 @@ class HtmlReporter(Reporter):
fhtml.close()
# Save this file's information for the index file.
- self.files.append({
+ index_info = {
'nums': nums,
'par': n_par,
'html_filename': html_filename,
- 'cu': cu,
- })
+ 'name': cu.name,
+ }
+ self.files.append(index_info)
+ self.status.set_index_info(flat_rootname, index_info)
def index_file(self):
"""Write the index.html file for this report."""
- index_tmpl = Templite(data("htmlfiles/index.html"), globals())
+ index_tmpl = Templite(
+ data("htmlfiles/index.html"), self.template_globals
+ )
files = self.files
arcs = self.arcs
@@ -173,6 +218,84 @@ class HtmlReporter(Reporter):
finally:
fhtml.close()
+ # Write the latest hashes for next time.
+ self.status.write(self.directory)
+
+
+class HtmlStatus(object):
+ """The status information we keep to support incremental reporting."""
+
+ STATUS_FILE = "status.dat"
+ STATUS_FORMAT = 1
+
+ def __init__(self):
+ self.reset()
+
+ def reset(self):
+ """Initialize to empty."""
+ self.settings = ''
+ self.files = {}
+
+ def read(self, directory):
+ """Read the last status in `directory`."""
+ usable = False
+ try:
+ status_file = os.path.join(directory, self.STATUS_FILE)
+ status = pickle.load(open(status_file, "rb"))
+ except IOError:
+ usable = False
+ else:
+ usable = True
+ if status['format'] != self.STATUS_FORMAT:
+ usable = False
+ elif status['version'] != coverage.__version__:
+ usable = False
+
+ if usable:
+ self.files = status['files']
+ self.settings = status['settings']
+ else:
+ self.reset()
+
+ def write(self, directory):
+ """Write the current status to `directory`."""
+ status_file = os.path.join(directory, self.STATUS_FILE)
+ status = {
+ 'format': self.STATUS_FORMAT,
+ 'version': coverage.__version__,
+ 'settings': self.settings,
+ 'files': self.files,
+ }
+ fout = open(status_file, "wb")
+ try:
+ pickle.dump(status, fout)
+ finally:
+ fout.close()
+
+ def settings_hash(self):
+ """Get the hash of the coverage.py settings."""
+ return self.settings
+
+ def set_settings_hash(self, settings):
+ """Set the hash of the coverage.py settings."""
+ self.settings = settings
+
+ def file_hash(self, fname):
+ """Get the hash of `fname`'s contents."""
+ return self.files.get(fname, {}).get('hash', '')
+
+ def set_file_hash(self, fname, val):
+ """Set the hash of `fname`'s contents."""
+ self.files.setdefault(fname, {})['hash'] = val
+
+ def index_info(self, fname):
+ """Get the information for index.html for `fname`."""
+ return self.files.get(fname, {}).get('index', {})
+
+ def set_index_info(self, fname, info):
+ """Set the information for index.html for `fname`."""
+ self.files.setdefault(fname, {})['index'] = info
+
# Helpers for templates and generating HTML