1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
import os
import glob
import json
from jinja2 import Template
MONTAGELIB = os.path.join('../..', 'MontageLib')
CTYPE = {}
CTYPE['int'] = 'int '
CTYPE['int*'] = 'int *'
CTYPE['integer'] = 'int '
CTYPE['char'] = 'char '
CTYPE['string'] = 'char *'
CTYPE['string*'] = 'char *'
CTYPE['boolean'] = 'int '
CTYPE['boolean*'] = 'int *'
CTYPE['double'] = 'double '
CTYPE['double*'] = 'double *'
PTYPE = {}
PTYPE['int'] = 'int'
PTYPE['int*'] = 'np.ndarray'
PTYPE['integer'] = 'int'
PTYPE['char'] = 'str'
PTYPE['string'] = 'str'
PTYPE['string*'] = 'str'
PTYPE['boolean'] = 'bool'
PTYPE['boolean*'] = 'np.ndarray'
PTYPE['double'] = 'float'
PTYPE['double*'] = 'np.ndarray'
with open('templates/template.pxd', 'r') as f:
template_pxd = Template(f.read())
with open('templates/template.pyx', 'r') as f:
template_pyx = Template(f.read())
with open('templates/template_main.pyx', 'r') as f:
template_main_pyx = Template(f.read())
functions = []
for json_file in glob.glob(os.path.join(MONTAGELIB, '*', '*.json')):
print("Parsing {0}...".format(json_file))
with open(json_file, 'r') as fjson:
data = json.load(fjson)
if data['return'] is None:
continue
# We set up our own dictionary that we will then pass on to the jinja2
# templates.
function = {}
# The name and description of the function
function['name'] = data['function']
function['summary'] = data['desc']
# We now compile a list of arguments with defaults and arguments without
# defaults - this is used in several places below. The arguments without
# defaults come first.
sorted_args = [arg for arg in data['arguments'] if 'default' not in arg]
sorted_args += [arg for arg in data['arguments'] if 'default' in arg]
# We now set up the lists of arguments.
# Normal list of arguments
function['arguments'] = [arg['name'] for arg in data['arguments']]
# List of arguments to use in the C function declaration (functions
# defined using cdef).
function['arguments_cdef'] = []
# List of arguments to use when calling the cdef wrapper from the normal
# Cython function - this has to include converting string arguments to
# bytes strings with .encode('ascii') and converting arrays with e.g.
# .data.as_doubles.
function['arguments_py_to_cdef'] = []
for arg in data['arguments']:
argument = "{0}{1}".format(CTYPE[arg['type']], arg['name'])
function['arguments_cdef'].append(argument)
function['arguments_with_defaults'] = []
for arg in sorted_args:
if 'default' in arg:
function['arguments_with_defaults'].append(arg['name'] + '=' + repr(arg['default']))
else:
function['arguments_with_defaults'].append(arg['name'])
function['array'] = []
function['arguments_py_to_cdef'] = []
for arg in data['arguments']:
if arg['type'] == 'double*':
function['array'].append("cdef _array.array {0}_arr = _array.array('d', {0})".format(arg['name']))
function['arguments_py_to_cdef'].append('{0}_arr.data.as_doubles'.format(arg['name']))
elif arg['type'] == 'int*':
function['array'].append("cdef _array.array {0}_arr = _array.array('i', {0})".format(arg['name']))
function['arguments_py_to_cdef'].append('{0}_arr.data.as_ints'.format(arg['name']))
elif arg['type'] == 'boolean*':
function['array'].append("cdef _array.array {0}_arr = _array.array('i', {0})".format(arg['name']))
function['arguments_py_to_cdef'].append('{0}_arr.data.as_ints'.format(arg['name']))
else:
if 'string' in arg['type']:
function['arguments_py_to_cdef'].append(arg['name'] + ".encode('ascii')")
else:
function['arguments_py_to_cdef'].append(arg['name'])
function['struct_vars'] = []
function['struct_vars_decl'] = []
for ret in data['return']:
struct_var = "{0}{1}".format(CTYPE[ret['type']], ret['name'])
function['struct_vars'].append(ret['name'])
function['struct_vars_decl'].append(struct_var)
function['docstring_arguments'] = []
for inp in sorted_args:
arg = {}
arg['name'] = inp['name']
arg['type'] = PTYPE[inp['type']]
if 'default' in inp:
arg['type'] += ", optional"
arg['description'] = inp['desc']
function['docstring_arguments'].append(arg)
function['return_arguments'] = []
for ret in data['return']:
arg = {}
arg['name'] = ret['name']
arg['type'] = PTYPE[ret['type']]
arg['description'] = ret['desc']
function['return_arguments'].append(arg)
functions.append(function)
with open('MontagePy/wrappers.pxd', 'w') as f:
f.write(template_pxd.render(functions=functions))
with open('MontagePy/_wrappers.pyx', 'w') as f:
f.write(template_pyx.render(functions=functions))
with open('MontagePy/main.pyx', 'w') as f:
f.write(template_main_pyx.render(functions=functions))
|