Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify and remove javascript from html_annotate templates. #2793

Merged
merged 15 commits into from
Jun 20, 2018
5 changes: 3 additions & 2 deletions docs/source/reference/jit-compilation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,13 @@ Dispatcher objects

The pure Python function which was compiled.

.. method:: inspect_types(file=None)
.. method:: inspect_types(file=None, pretty=False)

Print out a listing of the function source code annotated line-by-line
with the corresponding Numba IR, and the inferred types of the various
variables. If *file* is specified, printing is done to that file
object, otherwise to sys.stdout.
object, otherwise to sys.stdout. If *pretty* is set to True then colored
ANSI will be produced in a terminal and HTML in a notebook.

.. seealso:: :ref:`architecture`

Expand Down
171 changes: 85 additions & 86 deletions numba/annotations/template.html

Large diffs are not rendered by default.

61 changes: 46 additions & 15 deletions numba/annotations/type_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from collections import Mapping, defaultdict, OrderedDict
from contextlib import closing
import copy
import inspect
import os
import re
Expand Down Expand Up @@ -147,6 +148,48 @@ def annotate(self):
return io.getvalue()

def html_annotate(self, outfile):
# ensure that annotation information is assembled
self.annotate_raw()
# make a deep copy ahead of the pending mutations
func_data = copy.deepcopy(self.func_data)

key = 'python_indent'
for this_func in func_data.values():
if key in this_func:
idents = {}
for line, amount in this_func[key].items():
idents[line] = ' ' * amount
this_func[key] = idents

key = 'ir_indent'
for this_func in func_data.values():
if key in this_func:
idents = {}
for line, ir_id in this_func[key].items():
idents[line] = [' ' * amount for amount in ir_id]
this_func[key] = idents



try:
from jinja2 import Template
except ImportError:
raise ImportError("please install the 'jinja2' package")

root = os.path.join(os.path.dirname(__file__))
template_filename = os.path.join(root, 'template.html')
with open(template_filename, 'r') as template:
html = template.read()

template = Template(html)
rendered = template.render(func_data=func_data)
outfile.write(rendered)

def annotate_raw(self):
"""
This returns "raw" annotation information i.e. it has no output format
specific markup included.
"""
python_source = SourceLines(self.func_id.func)
ir_lines = self.prepare_annotations()
line_nums = [num for num in python_source]
Expand All @@ -160,7 +203,7 @@ def add_ir_line(func_data, line):
line_type = 'pyobject'
func_data['ir_lines'][num].append((line_str, line_type))
indent_len = len(_getindent(line))
func_data['ir_indent'][num].append(' ' * indent_len)
func_data['ir_indent'][num].append(indent_len)

func_key = (self.func_id.filename + ':' + str(self.func_id.firstlineno + 1),
self.signature)
Expand Down Expand Up @@ -211,7 +254,7 @@ def add_ir_line(func_data, line):
for num in line_nums:
func_data['python_lines'].append((num, python_source[num].strip()))
indent_len = len(_getindent(python_source[num]))
func_data['python_indent'][num] = ' ' * indent_len
func_data['python_indent'][num] = indent_len
func_data['python_tags'][num] = ''
func_data['ir_lines'][num] = []
func_data['ir_indent'][num] = []
Expand All @@ -222,20 +265,8 @@ def add_ir_line(func_data, line):
func_data['python_tags'][num] = 'lifted_tag'
elif line.strip().endswith('pyobject'):
func_data['python_tags'][num] = 'object_tag'
return self.func_data

try:
from jinja2 import Template
except ImportError:
raise ImportError("please install the 'jinja2' package")

root = os.path.join(os.path.dirname(__file__))
template_filename = os.path.join(root, 'template.html')
with open(template_filename, 'r') as template:
html = template.read()

template = Template(html)
rendered = template.render(func_data=TypeAnnotation.func_data)
outfile.write(rendered)

def __str__(self):
return self.annotate()
Expand Down
43 changes: 35 additions & 8 deletions numba/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,31 @@ def inspect_asm(self, signature=None):

return dict((sig, self.inspect_asm(sig)) for sig in self.signatures)

def inspect_types(self, file=None):
if file is None:
file = sys.stdout
def inspect_types(self, file=None, **kwargs):
"""
print or return annotated source with Numba intermediate IR

Pass `pretty=True` to attempt color highlighting, and HTML rendering in
Jupyter and IPython by returning an Annotate Object. `file` must be
None if used in conjunction with `pretty=True`.
"""
pretty = kwargs.get('pretty', False)
style = kwargs.get('style', 'default')

for ver, res in utils.iteritems(self.overloads):
print("%s %s" % (self.py_func.__name__, ver), file=file)
print('-' * 80, file=file)
print(res.type_annotation, file=file)
print('=' * 80, file=file)
if not pretty:
if file is None:
file = sys.stdout

for ver, res in utils.iteritems(self.overloads):
print("%s %s" % (self.py_func.__name__, ver), file=file)
print('-' * 80, file=file)
print(res.type_annotation, file=file)
print('=' * 80, file=file)
else:
if file is not None:
raise ValueError("`file` must be None if `pretty=True`")
from .pretty_annotate import Annotate
return Annotate(self, style=style)

def inspect_cfg(self, signature=None, show_wrapper=None):
"""
Expand All @@ -405,6 +421,17 @@ def inspect_cfg(self, signature=None, show_wrapper=None):
return dict((sig, self.inspect_cfg(sig, show_wrapper=show_wrapper))
for sig in self.signatures)

def get_annotation_info(self, signature=None):
"""
Gets the annotation information for the function specified by
signature. If no signature is supplied a dictionary of signature to
annotation information is returned.
"""
if signature is not None:
cres = self.overloads[signature]
return cres.type_annotation.annotate_raw()
return dict((sig, self.annotate(sig)) for sig in self.signatures)

def _explain_ambiguous(self, *args, **kws):
"""
Callback for the C _Dispatcher object.
Expand Down