diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2011-04-10 08:42:31 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2011-04-10 08:42:31 -0400 |
commit | 52e07c90b77b1d07ed95a6195ec5d895f0988224 (patch) | |
tree | 325346a20aedac88b3297919f5c1c89f79de7aed /coverage/html.py | |
parent | d4dd809d27ad7f31431a4ef61309b6951ad41d9b (diff) | |
parent | 822b7c82f58bbd6f2b38cc98c7881cc405d0c69e (diff) | |
download | python-coveragepy-52e07c90b77b1d07ed95a6195ec5d895f0988224.tar.gz |
Merge Brett's __main__.py file for the tree.
Diffstat (limited to 'coverage/html.py')
-rw-r--r-- | coverage/html.py | 147 |
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 |