1import os 2import genapi 3 4from genapi import \ 5 TypeApi, GlobalVarApi, FunctionApi, BoolValuesApi 6 7import numpy_api 8 9# use annotated api when running under cpychecker 10h_template = r""" 11#if defined(_MULTIARRAYMODULE) || defined(WITH_CPYCHECKER_STEALS_REFERENCE_TO_ARG_ATTRIBUTE) 12 13typedef struct { 14 PyObject_HEAD 15 npy_bool obval; 16} PyBoolScalarObject; 17 18extern NPY_NO_EXPORT PyTypeObject PyArrayMapIter_Type; 19extern NPY_NO_EXPORT PyTypeObject PyArrayNeighborhoodIter_Type; 20extern NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[2]; 21 22%s 23 24#else 25 26#if defined(PY_ARRAY_UNIQUE_SYMBOL) 27#define PyArray_API PY_ARRAY_UNIQUE_SYMBOL 28#endif 29 30#if defined(NO_IMPORT) || defined(NO_IMPORT_ARRAY) 31extern void **PyArray_API; 32#else 33#if defined(PY_ARRAY_UNIQUE_SYMBOL) 34void **PyArray_API; 35#else 36static void **PyArray_API=NULL; 37#endif 38#endif 39 40%s 41 42#if !defined(NO_IMPORT_ARRAY) && !defined(NO_IMPORT) 43static int 44_import_array(void) 45{ 46 int st; 47 PyObject *numpy = PyImport_ImportModule("numpy.core._multiarray_umath"); 48 PyObject *c_api = NULL; 49 50 if (numpy == NULL) { 51 return -1; 52 } 53 c_api = PyObject_GetAttrString(numpy, "_ARRAY_API"); 54 Py_DECREF(numpy); 55 if (c_api == NULL) { 56 PyErr_SetString(PyExc_AttributeError, "_ARRAY_API not found"); 57 return -1; 58 } 59 60 if (!PyCapsule_CheckExact(c_api)) { 61 PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is not PyCapsule object"); 62 Py_DECREF(c_api); 63 return -1; 64 } 65 PyArray_API = (void **)PyCapsule_GetPointer(c_api, NULL); 66 Py_DECREF(c_api); 67 if (PyArray_API == NULL) { 68 PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is NULL pointer"); 69 return -1; 70 } 71 72 /* Perform runtime check of C API version */ 73 if (NPY_VERSION != PyArray_GetNDArrayCVersion()) { 74 PyErr_Format(PyExc_RuntimeError, "module compiled against "\ 75 "ABI version 0x%%x but this version of numpy is 0x%%x", \ 76 (int) NPY_VERSION, (int) PyArray_GetNDArrayCVersion()); 77 return -1; 78 } 79 if (NPY_FEATURE_VERSION > PyArray_GetNDArrayCFeatureVersion()) { 80 PyErr_Format(PyExc_RuntimeError, "module compiled against "\ 81 "API version 0x%%x but this version of numpy is 0x%%x", \ 82 (int) NPY_FEATURE_VERSION, (int) PyArray_GetNDArrayCFeatureVersion()); 83 return -1; 84 } 85 86 /* 87 * Perform runtime check of endianness and check it matches the one set by 88 * the headers (npy_endian.h) as a safeguard 89 */ 90 st = PyArray_GetEndianness(); 91 if (st == NPY_CPU_UNKNOWN_ENDIAN) { 92 PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as unknown endian"); 93 return -1; 94 } 95#if NPY_BYTE_ORDER == NPY_BIG_ENDIAN 96 if (st != NPY_CPU_BIG) { 97 PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as "\ 98 "big endian, but detected different endianness at runtime"); 99 return -1; 100 } 101#elif NPY_BYTE_ORDER == NPY_LITTLE_ENDIAN 102 if (st != NPY_CPU_LITTLE) { 103 PyErr_Format(PyExc_RuntimeError, "FATAL: module compiled as "\ 104 "little endian, but detected different endianness at runtime"); 105 return -1; 106 } 107#endif 108 109 return 0; 110} 111 112#define import_array() {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); return NULL; } } 113 114#define import_array1(ret) {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); return ret; } } 115 116#define import_array2(msg, ret) {if (_import_array() < 0) {PyErr_Print(); PyErr_SetString(PyExc_ImportError, msg); return ret; } } 117 118#endif 119 120#endif 121""" 122 123 124c_template = r""" 125/* These pointers will be stored in the C-object for use in other 126 extension modules 127*/ 128 129void *PyArray_API[] = { 130%s 131}; 132""" 133 134c_api_header = """ 135=========== 136NumPy C-API 137=========== 138""" 139 140def generate_api(output_dir, force=False): 141 basename = 'multiarray_api' 142 143 h_file = os.path.join(output_dir, '__%s.h' % basename) 144 c_file = os.path.join(output_dir, '__%s.c' % basename) 145 d_file = os.path.join(output_dir, '%s.txt' % basename) 146 targets = (h_file, c_file, d_file) 147 148 sources = numpy_api.multiarray_api 149 150 if (not force and not genapi.should_rebuild(targets, [numpy_api.__file__, __file__])): 151 return targets 152 else: 153 do_generate_api(targets, sources) 154 155 return targets 156 157def do_generate_api(targets, sources): 158 header_file = targets[0] 159 c_file = targets[1] 160 doc_file = targets[2] 161 162 global_vars = sources[0] 163 scalar_bool_values = sources[1] 164 types_api = sources[2] 165 multiarray_funcs = sources[3] 166 167 multiarray_api = sources[:] 168 169 module_list = [] 170 extension_list = [] 171 init_list = [] 172 173 # Check multiarray api indexes 174 multiarray_api_index = genapi.merge_api_dicts(multiarray_api) 175 genapi.check_api_dict(multiarray_api_index) 176 177 numpyapi_list = genapi.get_api_functions('NUMPY_API', 178 multiarray_funcs) 179 180 # FIXME: ordered_funcs_api is unused 181 ordered_funcs_api = genapi.order_dict(multiarray_funcs) 182 183 # Create dict name -> *Api instance 184 api_name = 'PyArray_API' 185 multiarray_api_dict = {} 186 for f in numpyapi_list: 187 name = f.name 188 index = multiarray_funcs[name][0] 189 annotations = multiarray_funcs[name][1:] 190 multiarray_api_dict[f.name] = FunctionApi(f.name, index, annotations, 191 f.return_type, 192 f.args, api_name) 193 194 for name, val in global_vars.items(): 195 index, type = val 196 multiarray_api_dict[name] = GlobalVarApi(name, index, type, api_name) 197 198 for name, val in scalar_bool_values.items(): 199 index = val[0] 200 multiarray_api_dict[name] = BoolValuesApi(name, index, api_name) 201 202 for name, val in types_api.items(): 203 index = val[0] 204 internal_type = None if len(val) == 1 else val[1] 205 multiarray_api_dict[name] = TypeApi( 206 name, index, 'PyTypeObject', api_name, internal_type) 207 208 if len(multiarray_api_dict) != len(multiarray_api_index): 209 keys_dict = set(multiarray_api_dict.keys()) 210 keys_index = set(multiarray_api_index.keys()) 211 raise AssertionError( 212 "Multiarray API size mismatch - " 213 "index has extra keys {}, dict has extra keys {}" 214 .format(keys_index - keys_dict, keys_dict - keys_index) 215 ) 216 217 extension_list = [] 218 for name, index in genapi.order_dict(multiarray_api_index): 219 api_item = multiarray_api_dict[name] 220 extension_list.append(api_item.define_from_array_api_string()) 221 init_list.append(api_item.array_api_define()) 222 module_list.append(api_item.internal_define()) 223 224 # Write to header 225 s = h_template % ('\n'.join(module_list), '\n'.join(extension_list)) 226 genapi.write_file(header_file, s) 227 228 # Write to c-code 229 s = c_template % ',\n'.join(init_list) 230 genapi.write_file(c_file, s) 231 232 # write to documentation 233 s = c_api_header 234 for func in numpyapi_list: 235 s += func.to_ReST() 236 s += '\n\n' 237 genapi.write_file(doc_file, s) 238 239 return targets 240