Aluode/PerceptionLabPortable
0
1"""
2Generate documentation for all registered implementation for lowering
3using reStructured text.
4"""
5
6
7from subprocess import check_output
8
9import os.path
10try:
11 from StringIO import StringIO # py2
12except ImportError:
13 from io import StringIO
14from collections import defaultdict
15import inspect
16from functools import partial
17
18import numba
19from numba.core.registry import cpu_target
20
21
22def git_hash():
23 out = check_output(['git', 'log', "--pretty=format:'%H'", '-n', '1'])
24 return out.decode('ascii').strip("'\"")
25
26
27def get_func_name(fn):
28 return getattr(fn, '__qualname__', fn.__name__)
29
30
31def gather_function_info(backend):
32 fninfos = defaultdict(list)
33 basepath = os.path.dirname(os.path.dirname(numba.__file__))
34 for fn, osel in backend._defns.items():
35 for sig, impl in osel.versions:
36 info = {}
37 fninfos[fn].append(info)
38 info['fn'] = fn
39 info['sig'] = sig
40 code, firstlineno = inspect.getsourcelines(impl)
41 path = inspect.getsourcefile(impl)
42 info['impl'] = {
43 'name': get_func_name(impl),
44 'filename': os.path.relpath(path, start=basepath),
45 'lines': (firstlineno, firstlineno + len(code) - 1),
46 'docstring': impl.__doc__
47 }
48
49 return fninfos
50
51
52def bind_file_to_print(fobj):
53 return partial(print, file=fobj)
54
55
56def format_signature(sig):
57 def fmt(c):
58 try:
59 return c.__name__
60 except AttributeError:
61 return repr(c).strip('\'"')
62 out = tuple(map(fmt, sig))
63 return '`({0})`'.format(', '.join(out))
64
65
66github_url = ('https://github.com/numba/numba/blob/'
67 '{commit}/{path}#L{firstline}-L{lastline}')
68
69description = """
70This lists all lowering definition registered to the CPU target.
71Each subsection corresponds to a Python function that is supported by numba
72nopython mode. These functions have one or more lower implementation with
73different signatures. The compiler chooses the most specific implementation
74from all overloads.
75"""
76
77
78def format_function_infos(fninfos):
79 buf = StringIO()
80 try:
81 print = bind_file_to_print(buf)
82
83 title_line = "Lowering Listing"
84 print(title_line)
85 print('=' * len(title_line))
86
87 print(description)
88
89 commit = git_hash()
90
91 def format_fname(fn):
92 try:
93 fname = "{0}.{1}".format(fn.__module__, get_func_name(fn))
94 except AttributeError:
95 fname = repr(fn)
96 return fn, fname
97
98 for fn, fname in sorted(map(format_fname, fninfos), key=lambda x: x[1]):
99 impinfos = fninfos[fn]
100 header_line = "``{0}``".format(fname)
101 print(header_line)
102 print('-' * len(header_line))
103 print()
104
105 formatted_sigs = map(
106 lambda x: format_signature(x['sig']), impinfos)
107 sorted_impinfos = sorted(zip(formatted_sigs, impinfos),
108 key=lambda x: x[0])
109
110 col_signatures = ['Signature']
111 col_urls = ['Definition']
112
113 for fmtsig, info in sorted_impinfos:
114 impl = info['impl']
115
116 filename = impl['filename']
117 lines = impl['lines']
118 fname = impl['name']
119
120 source = '{0} lines {1}-{2}'.format(filename, *lines)
121 link = github_url.format(commit=commit, path=filename,
122 firstline=lines[0], lastline=lines[1])
123 url = '``{0}`` `{1} <{2}>`_'.format(fname, source, link)
124
125 col_signatures.append(fmtsig)
126 col_urls.append(url)
127
128 # table formatting
129 max_width_col_sig = max(map(len, col_signatures))
130 max_width_col_url = max(map(len, col_urls))
131 padding = 2
132 width_col_sig = padding * 2 + max_width_col_sig
133 width_col_url = padding * 2 + max_width_col_url
134 line_format = "{{0:^{0}}} {{1:^{1}}}".format(width_col_sig,
135 width_col_url)
136 print(line_format.format('=' * width_col_sig, '=' * width_col_url))
137 print(line_format.format(col_signatures[0], col_urls[0]))
138 print(line_format.format('=' * width_col_sig, '=' * width_col_url))
139 for sig, url in zip(col_signatures[1:], col_urls[1:]):
140 print(line_format.format(sig, url))
141 print(line_format.format('=' * width_col_sig, '=' * width_col_url))
142 print()
143
144 return buf.getvalue()
145 finally:
146 buf.close()
147
148
149# Main routine for this module:
150
151def gen_lower_listing(path=None):
152 """
153 Generate lowering listing to ``path`` or (if None) to stdout.
154 """
155 cpu_backend = cpu_target.target_context
156 cpu_backend.refresh()
157
158 fninfos = gather_function_info(cpu_backend)
159 out = format_function_infos(fninfos)
160
161 if path is None:
162 print(out)
163 else:
164 with open(path, 'w') as fobj:
165 print(out, file=fobj)
166
167
168if __name__ == '__main__':
169 gen_lower_listing()
170 