| Index: third_party/coverage-3.6/coverage/html.py
|
| diff --git a/third_party/coverage-3.6/coverage/html.py b/third_party/coverage-3.6/coverage/html.py
|
| deleted file mode 100644
|
| index ed8920f21e8a208dc1f8c53e8d27279c5e06d372..0000000000000000000000000000000000000000
|
| --- a/third_party/coverage-3.6/coverage/html.py
|
| +++ /dev/null
|
| @@ -1,367 +0,0 @@
|
| -"""HTML reporting for Coverage."""
|
| -
|
| -import os, re, shutil, sys
|
| -
|
| -import coverage
|
| -from coverage.backward import pickle
|
| -from coverage.misc import CoverageException, Hasher
|
| -from coverage.phystokens import source_token_lines, source_encoding
|
| -from coverage.report import Reporter
|
| -from coverage.results import Numbers
|
| -from coverage.templite import Templite
|
| -
|
| -# Disable pylint msg W0612, because a bunch of variables look unused, but
|
| -# they're accessed in a Templite context via locals().
|
| -# pylint: disable=W0612
|
| -
|
| -def data_filename(fname):
|
| - """Return the path to a data file of ours."""
|
| - return os.path.join(os.path.split(__file__)[0], fname)
|
| -
|
| -def data(fname):
|
| - """Return the contents of a data file of ours."""
|
| - data_file = open(data_filename(fname))
|
| - try:
|
| - return data_file.read()
|
| - finally:
|
| - data_file.close()
|
| -
|
| -
|
| -class HtmlReporter(Reporter):
|
| - """HTML reporting."""
|
| -
|
| - # These files will be copied from the htmlfiles dir to the output dir.
|
| - STATIC_FILES = [
|
| - "style.css",
|
| - "jquery-1.4.3.min.js",
|
| - "jquery.hotkeys.js",
|
| - "jquery.isonscreen.js",
|
| - "jquery.tablesorter.min.js",
|
| - "coverage_html.js",
|
| - "keybd_closed.png",
|
| - "keybd_open.png",
|
| - ]
|
| -
|
| - def __init__(self, cov, config):
|
| - super(HtmlReporter, self).__init__(cov, config)
|
| - self.directory = None
|
| - self.template_globals = {
|
| - 'escape': escape,
|
| - 'title': self.config.html_title,
|
| - '__url__': coverage.__url__,
|
| - '__version__': coverage.__version__,
|
| - }
|
| - self.source_tmpl = Templite(
|
| - data("htmlfiles/pyfile.html"), self.template_globals
|
| - )
|
| -
|
| - self.coverage = cov
|
| -
|
| - self.files = []
|
| - self.arcs = self.coverage.data.has_arcs()
|
| - self.status = HtmlStatus()
|
| - self.extra_css = None
|
| - self.totals = Numbers()
|
| -
|
| - def report(self, morfs):
|
| - """Generate an HTML report for `morfs`.
|
| -
|
| - `morfs` is a list of modules or filenames.
|
| -
|
| - """
|
| - assert self.config.html_dir, "must give a directory for html reporting"
|
| -
|
| - # Read the status data.
|
| - self.status.read(self.config.html_dir)
|
| -
|
| - # Check that this run used the same settings as the last run.
|
| - m = Hasher()
|
| - m.update(self.config)
|
| - these_settings = m.digest()
|
| - if self.status.settings_hash() != these_settings:
|
| - self.status.reset()
|
| - self.status.set_settings_hash(these_settings)
|
| -
|
| - # The user may have extra CSS they want copied.
|
| - if self.config.extra_css:
|
| - self.extra_css = os.path.basename(self.config.extra_css)
|
| -
|
| - # Process all the files.
|
| - self.report_files(self.html_file, morfs, self.config.html_dir)
|
| -
|
| - if not self.files:
|
| - raise CoverageException("No data to report.")
|
| -
|
| - # Write the index file.
|
| - self.index_file()
|
| -
|
| - self.make_local_static_report_files()
|
| -
|
| - return self.totals.pc_covered
|
| -
|
| - def make_local_static_report_files(self):
|
| - """Make local instances of static files for HTML report."""
|
| - # The files we provide must always be copied.
|
| - for static in self.STATIC_FILES:
|
| - shutil.copyfile(
|
| - data_filename("htmlfiles/" + static),
|
| - os.path.join(self.directory, static)
|
| - )
|
| -
|
| - # The user may have extra CSS they want copied.
|
| - if self.extra_css:
|
| - shutil.copyfile(
|
| - self.config.extra_css,
|
| - os.path.join(self.directory, self.extra_css)
|
| - )
|
| -
|
| - def write_html(self, fname, html):
|
| - """Write `html` to `fname`, properly encoded."""
|
| - fout = open(fname, "wb")
|
| - try:
|
| - fout.write(html.encode('ascii', 'xmlcharrefreplace'))
|
| - finally:
|
| - fout.close()
|
| -
|
| - 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()
|
| - try:
|
| - source = source_file.read()
|
| - 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)
|
| -
|
| - # If need be, determine the encoding of the source file. We use it
|
| - # later to properly write the HTML.
|
| - if sys.version_info < (3, 0):
|
| - encoding = source_encoding(source)
|
| - # Some UTF8 files have the dreaded UTF8 BOM. If so, junk it.
|
| - if encoding.startswith("utf-8") and source[:3] == "\xef\xbb\xbf":
|
| - source = source[3:]
|
| - encoding = "utf-8"
|
| -
|
| - # Get the numbers for this file.
|
| - nums = analysis.numbers
|
| -
|
| - missing_branch_arcs = analysis.missing_branch_arcs()
|
| - arcs = self.arcs
|
| -
|
| - # These classes determine which lines are highlighted by default.
|
| - c_run = "run hide_run"
|
| - c_exc = "exc"
|
| - c_mis = "mis"
|
| - c_par = "par " + c_run
|
| -
|
| - lines = []
|
| -
|
| - for lineno, line in enumerate(source_token_lines(source)):
|
| - lineno += 1 # 1-based line numbers.
|
| - # Figure out how to mark this line.
|
| - line_class = []
|
| - annotate_html = ""
|
| - annotate_title = ""
|
| - if lineno in analysis.statements:
|
| - line_class.append("stm")
|
| - if lineno in analysis.excluded:
|
| - line_class.append(c_exc)
|
| - elif lineno in analysis.missing:
|
| - line_class.append(c_mis)
|
| - elif self.arcs and lineno in missing_branch_arcs:
|
| - line_class.append(c_par)
|
| - annlines = []
|
| - for b in missing_branch_arcs[lineno]:
|
| - if b < 0:
|
| - annlines.append("exit")
|
| - else:
|
| - annlines.append(str(b))
|
| - annotate_html = " ".join(annlines)
|
| - if len(annlines) > 1:
|
| - annotate_title = "no jumps to these line numbers"
|
| - elif len(annlines) == 1:
|
| - annotate_title = "no jump to this line number"
|
| - elif lineno in analysis.statements:
|
| - line_class.append(c_run)
|
| -
|
| - # Build the HTML for the line
|
| - html = []
|
| - for tok_type, tok_text in line:
|
| - if tok_type == "ws":
|
| - html.append(escape(tok_text))
|
| - else:
|
| - tok_html = escape(tok_text) or ' '
|
| - html.append(
|
| - "<span class='%s'>%s</span>" % (tok_type, tok_html)
|
| - )
|
| -
|
| - lines.append({
|
| - 'html': ''.join(html),
|
| - 'number': lineno,
|
| - 'class': ' '.join(line_class) or "pln",
|
| - 'annotate': annotate_html,
|
| - 'annotate_title': annotate_title,
|
| - })
|
| -
|
| - # Write the HTML page for this file.
|
| - html_filename = flat_rootname + ".html"
|
| - html_path = os.path.join(self.directory, html_filename)
|
| - extra_css = self.extra_css
|
| -
|
| - html = spaceless(self.source_tmpl.render(locals()))
|
| - if sys.version_info < (3, 0):
|
| - html = html.decode(encoding)
|
| - self.write_html(html_path, html)
|
| -
|
| - # Save this file's information for the index file.
|
| - index_info = {
|
| - 'nums': nums,
|
| - 'html_filename': html_filename,
|
| - '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"), self.template_globals
|
| - )
|
| -
|
| - files = self.files
|
| - arcs = self.arcs
|
| -
|
| - self.totals = totals = sum([f['nums'] for f in files])
|
| - extra_css = self.extra_css
|
| -
|
| - html = index_tmpl.render(locals())
|
| - if sys.version_info < (3, 0):
|
| - html = html.decode("utf-8")
|
| - self.write_html(
|
| - os.path.join(self.directory, "index.html"),
|
| - html
|
| - )
|
| -
|
| - # 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)
|
| - fstatus = open(status_file, "rb")
|
| - try:
|
| - status = pickle.load(fstatus)
|
| - finally:
|
| - fstatus.close()
|
| - except (IOError, ValueError):
|
| - 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
|
| -
|
| -def escape(t):
|
| - """HTML-escape the text in `t`."""
|
| - return (t
|
| - # Convert HTML special chars into HTML entities.
|
| - .replace("&", "&").replace("<", "<").replace(">", ">")
|
| - .replace("'", "'").replace('"', """)
|
| - # Convert runs of spaces: "......" -> " . . ."
|
| - .replace(" ", " ")
|
| - # To deal with odd-length runs, convert the final pair of spaces
|
| - # so that "....." -> " . ."
|
| - .replace(" ", " ")
|
| - )
|
| -
|
| -def spaceless(html):
|
| - """Squeeze out some annoying extra space from an HTML string.
|
| -
|
| - Nicely-formatted templates mean lots of extra space in the result.
|
| - Get rid of some.
|
| -
|
| - """
|
| - html = re.sub(r">\s+<p ", ">\n<p ", html)
|
| - return html
|
|
|