diff options
author | orivej <[email protected]> | 2022-02-10 16:44:49 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:44:49 +0300 |
commit | 718c552901d703c502ccbefdfc3c9028d608b947 (patch) | |
tree | 46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/tools/cython/Cython/Compiler/Annotate.py | |
parent | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff) |
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/Annotate.py')
-rw-r--r-- | contrib/tools/cython/Cython/Compiler/Annotate.py | 228 |
1 files changed, 114 insertions, 114 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/Annotate.py b/contrib/tools/cython/Cython/Compiler/Annotate.py index 2ea38c00c74..c8a1d9be77d 100644 --- a/contrib/tools/cython/Cython/Compiler/Annotate.py +++ b/contrib/tools/cython/Cython/Compiler/Annotate.py @@ -3,21 +3,21 @@ from __future__ import absolute_import import os -import os.path +import os.path import re import codecs import textwrap -from datetime import datetime -from functools import partial -from collections import defaultdict +from datetime import datetime +from functools import partial +from collections import defaultdict try: from xml.sax.saxutils import escape as html_escape except ImportError: pass -try: - from StringIO import StringIO -except ImportError: - from io import StringIO # does not support writing 'str' in Py2 +try: + from StringIO import StringIO +except ImportError: + from io import StringIO # does not support writing 'str' in Py2 from . import Version from .Code import CCodeWriter @@ -27,23 +27,23 @@ from .. import Utils class AnnotationCCodeWriter(CCodeWriter): def __init__(self, create_from=None, buffer=None, copy_formatting=True): - CCodeWriter.__init__(self, create_from, buffer, copy_formatting=copy_formatting) + CCodeWriter.__init__(self, create_from, buffer, copy_formatting=copy_formatting) if create_from is None: self.annotation_buffer = StringIO() - self.last_annotated_pos = None - # annotations[filename][line] -> [(column, AnnotationItem)*] - self.annotations = defaultdict(partial(defaultdict, list)) - # code[filename][line] -> str - self.code = defaultdict(partial(defaultdict, str)) - # scopes[filename][line] -> set(scopes) - self.scopes = defaultdict(partial(defaultdict, set)) + self.last_annotated_pos = None + # annotations[filename][line] -> [(column, AnnotationItem)*] + self.annotations = defaultdict(partial(defaultdict, list)) + # code[filename][line] -> str + self.code = defaultdict(partial(defaultdict, str)) + # scopes[filename][line] -> set(scopes) + self.scopes = defaultdict(partial(defaultdict, set)) else: # When creating an insertion point, keep references to the same database self.annotation_buffer = create_from.annotation_buffer self.annotations = create_from.annotations self.code = create_from.code - self.scopes = create_from.scopes - self.last_annotated_pos = create_from.last_annotated_pos + self.scopes = create_from.scopes + self.last_annotated_pos = create_from.last_annotated_pos def create_new(self, create_from, buffer, copy_formatting): return AnnotationCCodeWriter(create_from, buffer, copy_formatting) @@ -52,54 +52,54 @@ class AnnotationCCodeWriter(CCodeWriter): CCodeWriter.write(self, s) self.annotation_buffer.write(s) - def mark_pos(self, pos, trace=True): + def mark_pos(self, pos, trace=True): if pos is not None: - CCodeWriter.mark_pos(self, pos, trace) - if self.funcstate and self.funcstate.scope: - # lambdas and genexprs can result in multiple scopes per line => keep them in a set - self.scopes[pos[0].filename][pos[1]].add(self.funcstate.scope) - if self.last_annotated_pos: - source_desc, line, _ = self.last_annotated_pos - pos_code = self.code[source_desc.filename] - pos_code[line] += self.annotation_buffer.getvalue() + CCodeWriter.mark_pos(self, pos, trace) + if self.funcstate and self.funcstate.scope: + # lambdas and genexprs can result in multiple scopes per line => keep them in a set + self.scopes[pos[0].filename][pos[1]].add(self.funcstate.scope) + if self.last_annotated_pos: + source_desc, line, _ = self.last_annotated_pos + pos_code = self.code[source_desc.filename] + pos_code[line] += self.annotation_buffer.getvalue() self.annotation_buffer = StringIO() - self.last_annotated_pos = pos + self.last_annotated_pos = pos def annotate(self, pos, item): - self.annotations[pos[0].filename][pos[1]].append((pos[2], item)) + self.annotations[pos[0].filename][pos[1]].append((pos[2], item)) def _css(self): """css template will later allow to choose a colormap""" css = [self._css_template] for i in range(255): color = u"FFFF%02x" % int(255/(1+i/10.0)) - css.append('.cython.score-%d {background-color: #%s;}' % (i, color)) + css.append('.cython.score-%d {background-color: #%s;}' % (i, color)) try: from pygments.formatters import HtmlFormatter except ImportError: pass - else: - css.append(HtmlFormatter().get_style_defs('.cython')) - return '\n'.join(css) + else: + css.append(HtmlFormatter().get_style_defs('.cython')) + return '\n'.join(css) _css_template = textwrap.dedent(""" body.cython { font-family: courier; font-size: 12; } .cython.tag { } .cython.line { margin: 0em } - .cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; } - - .cython.line .run { background-color: #B0FFB0; } - .cython.line .mis { background-color: #FFB0B0; } - .cython.code.run { border-left: 8px solid #B0FFB0; } - .cython.code.mis { border-left: 8px solid #FFB0B0; } + .cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; } + .cython.line .run { background-color: #B0FFB0; } + .cython.line .mis { background-color: #FFB0B0; } + .cython.code.run { border-left: 8px solid #B0FFB0; } + .cython.code.mis { border-left: 8px solid #FFB0B0; } + .cython.code .py_c_api { color: red; } .cython.code .py_macro_api { color: #FF7000; } .cython.code .pyx_c_api { color: #FF3000; } .cython.code .pyx_macro_api { color: #FF7000; } .cython.code .refnanny { color: #FFA000; } - .cython.code .trace { color: #FFA000; } + .cython.code .trace { color: #FFA000; } .cython.code .error_goto { color: #FFA000; } .cython.code .coerce { color: #008000; border: 1px dotted #008000 } @@ -117,22 +117,22 @@ class AnnotationCCodeWriter(CCodeWriter): ).replace(' ', '') # poor dev's JS minification ) - def save_annotation(self, source_filename, target_filename, coverage_xml=None): + def save_annotation(self, source_filename, target_filename, coverage_xml=None): with Utils.open_source_file(source_filename) as f: code = f.read() generated_code = self.code.get(source_filename, {}) c_file = Utils.decode_filename(os.path.basename(target_filename)) html_filename = os.path.splitext(target_filename)[0] + ".html" - + with codecs.open(html_filename, "w", encoding="UTF-8") as out_buffer: - out_buffer.write(self._save_annotation(code, generated_code, c_file, source_filename, coverage_xml)) - - def _save_annotation_header(self, c_file, source_filename, coverage_timestamp=None): - coverage_info = '' - if coverage_timestamp: - coverage_info = u' with coverage data from {timestamp}'.format( - timestamp=datetime.fromtimestamp(int(coverage_timestamp) // 1000)) - + out_buffer.write(self._save_annotation(code, generated_code, c_file, source_filename, coverage_xml)) + + def _save_annotation_header(self, c_file, source_filename, coverage_timestamp=None): + coverage_info = '' + if coverage_timestamp: + coverage_info = u' with coverage data from {timestamp}'.format( + timestamp=datetime.fromtimestamp(int(coverage_timestamp) // 1000)) + outlist = [ textwrap.dedent(u'''\ <!DOCTYPE html> @@ -140,20 +140,20 @@ class AnnotationCCodeWriter(CCodeWriter): <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title>Cython: {filename}</title> + <title>Cython: {filename}</title> <style type="text/css"> {css} </style> </head> <body class="cython"> - <p><span style="border-bottom: solid 1px grey;">Generated by Cython {watermark}</span>{more_info}</p> - <p> - <span style="background-color: #FFFF00">Yellow lines</span> hint at Python interaction.<br /> - Click on a line that starts with a "<code>+</code>" to see the C code that Cython generated for it. - </p> + <p><span style="border-bottom: solid 1px grey;">Generated by Cython {watermark}</span>{more_info}</p> + <p> + <span style="background-color: #FFFF00">Yellow lines</span> hint at Python interaction.<br /> + Click on a line that starts with a "<code>+</code>" to see the C code that Cython generated for it. + </p> ''').format(css=self._css(), watermark=Version.watermark, - filename=os.path.basename(source_filename) if source_filename else '', - more_info=coverage_info) + filename=os.path.basename(source_filename) if source_filename else '', + more_info=coverage_info) ] if c_file: outlist.append(u'<p>Raw output: <a href="%s">%s</a></p>\n' % (c_file, c_file)) @@ -162,45 +162,45 @@ class AnnotationCCodeWriter(CCodeWriter): def _save_annotation_footer(self): return (u'</body></html>\n',) - def _save_annotation(self, code, generated_code, c_file=None, source_filename=None, coverage_xml=None): + def _save_annotation(self, code, generated_code, c_file=None, source_filename=None, coverage_xml=None): """ lines : original cython source code split by lines generated_code : generated c code keyed by line number in original file target filename : name of the file in which to store the generated html c_file : filename in which the c_code has been written """ - if coverage_xml is not None and source_filename: - coverage_timestamp = coverage_xml.get('timestamp', '').strip() - covered_lines = self._get_line_coverage(coverage_xml, source_filename) - else: - coverage_timestamp = covered_lines = None - annotation_items = dict(self.annotations[source_filename]) - scopes = dict(self.scopes[source_filename]) - + if coverage_xml is not None and source_filename: + coverage_timestamp = coverage_xml.get('timestamp', '').strip() + covered_lines = self._get_line_coverage(coverage_xml, source_filename) + else: + coverage_timestamp = covered_lines = None + annotation_items = dict(self.annotations[source_filename]) + scopes = dict(self.scopes[source_filename]) + outlist = [] - outlist.extend(self._save_annotation_header(c_file, source_filename, coverage_timestamp)) - outlist.extend(self._save_annotation_body(code, generated_code, annotation_items, scopes, covered_lines)) + outlist.extend(self._save_annotation_header(c_file, source_filename, coverage_timestamp)) + outlist.extend(self._save_annotation_body(code, generated_code, annotation_items, scopes, covered_lines)) outlist.extend(self._save_annotation_footer()) return ''.join(outlist) - def _get_line_coverage(self, coverage_xml, source_filename): - coverage_data = None - for entry in coverage_xml.iterfind('.//class'): - if not entry.get('filename'): - continue - if (entry.get('filename') == source_filename or - os.path.abspath(entry.get('filename')) == source_filename): - coverage_data = entry - break - elif source_filename.endswith(entry.get('filename')): - coverage_data = entry # but we might still find a better match... - if coverage_data is None: - return None - return dict( - (int(line.get('number')), int(line.get('hits'))) - for line in coverage_data.iterfind('lines/line') - ) - + def _get_line_coverage(self, coverage_xml, source_filename): + coverage_data = None + for entry in coverage_xml.iterfind('.//class'): + if not entry.get('filename'): + continue + if (entry.get('filename') == source_filename or + os.path.abspath(entry.get('filename')) == source_filename): + coverage_data = entry + break + elif source_filename.endswith(entry.get('filename')): + coverage_data = entry # but we might still find a better match... + if coverage_data is None: + return None + return dict( + (int(line.get('number')), int(line.get('hits'))) + for line in coverage_data.iterfind('lines/line') + ) + def _htmlify_code(self, code): try: from pygments import highlight @@ -215,12 +215,12 @@ class AnnotationCCodeWriter(CCodeWriter): HtmlFormatter(nowrap=True)) return html_code - def _save_annotation_body(self, cython_code, generated_code, annotation_items, scopes, covered_lines=None): + def _save_annotation_body(self, cython_code, generated_code, annotation_items, scopes, covered_lines=None): outlist = [u'<div class="cython">'] pos_comment_marker = u'/* \N{HORIZONTAL ELLIPSIS} */\n' new_calls_map = dict( (name, 0) for name in - 'refnanny trace py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split() + 'refnanny trace py_macro_api py_c_api pyx_macro_api pyx_c_api error_goto'.split() ).copy self.mark_pos(None) @@ -228,13 +228,13 @@ class AnnotationCCodeWriter(CCodeWriter): def annotate(match): group_name = match.lastgroup calls[group_name] += 1 - return u"<span class='%s'>%s</span>" % ( + return u"<span class='%s'>%s</span>" % ( group_name, match.group(group_name)) lines = self._htmlify_code(cython_code).splitlines() lineno_width = len(str(len(lines))) - if not covered_lines: - covered_lines = None + if not covered_lines: + covered_lines = None for k, line in enumerate(lines, 1): try: @@ -259,48 +259,48 @@ class AnnotationCCodeWriter(CCodeWriter): onclick = '' expandsymbol = ' ' - covered = '' - if covered_lines is not None and k in covered_lines: - hits = covered_lines[k] - if hits is not None: - covered = 'run' if hits else 'mis' - + covered = '' + if covered_lines is not None and k in covered_lines: + hits = covered_lines[k] + if hits is not None: + covered = 'run' if hits else 'mis' + outlist.append( - u'<pre class="cython line score-{score}"{onclick}>' + u'<pre class="cython line score-{score}"{onclick}>' # generate line number with expand symbol in front, # and the right number of digit - u'{expandsymbol}<span class="{covered}">{line:0{lineno_width}d}</span>: {code}</pre>\n'.format( + u'{expandsymbol}<span class="{covered}">{line:0{lineno_width}d}</span>: {code}</pre>\n'.format( score=score, expandsymbol=expandsymbol, - covered=covered, + covered=covered, lineno_width=lineno_width, line=k, code=line.rstrip(), onclick=onclick, )) if c_code: - outlist.append(u"<pre class='cython code score-{score} {covered}'>{code}</pre>".format( - score=score, covered=covered, code=c_code)) + outlist.append(u"<pre class='cython code score-{score} {covered}'>{code}</pre>".format( + score=score, covered=covered, code=c_code)) outlist.append(u"</div>") return outlist -_parse_code = re.compile(( - br'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|' - br'(?P<trace>__Pyx_Trace[A-Za-z]+)|' - br'(?:' - br'(?P<pyx_macro_api>__Pyx_[A-Z][A-Z_]+)|' - br'(?P<pyx_c_api>(?:__Pyx_[A-Z][a-z_][A-Za-z_]*)|__pyx_convert_[A-Za-z_]*)|' - br'(?P<py_macro_api>Py[A-Z][a-z]+_[A-Z][A-Z_]+)|' - br'(?P<py_c_api>Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]*)' - br')(?=\()|' # look-ahead to exclude subsequent '(' from replacement +_parse_code = re.compile(( + br'(?P<refnanny>__Pyx_X?(?:GOT|GIVE)REF|__Pyx_RefNanny[A-Za-z]+)|' + br'(?P<trace>__Pyx_Trace[A-Za-z]+)|' + br'(?:' + br'(?P<pyx_macro_api>__Pyx_[A-Z][A-Z_]+)|' + br'(?P<pyx_c_api>(?:__Pyx_[A-Z][a-z_][A-Za-z_]*)|__pyx_convert_[A-Za-z_]*)|' + br'(?P<py_macro_api>Py[A-Z][a-z]+_[A-Z][A-Z_]+)|' + br'(?P<py_c_api>Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]*)' + br')(?=\()|' # look-ahead to exclude subsequent '(' from replacement br'(?P<error_goto>(?:(?<=;) *if [^;]* +)?__PYX_ERR\([^)]+\))' -).decode('ascii')).sub +).decode('ascii')).sub _replace_pos_comment = re.compile( # this matches what Cython generates as code line marker comment - br'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n'.decode('ascii'), + br'^\s*/\*(?:(?:[^*]|\*[^/])*\n)+\s*\*/\s*\n'.decode('ascii'), re.M ).sub |