1 module mir.pybind; 2 /** CODING GUIDE 3 4 D or Python: 5 6 When we can implement something both in D or Python, we do everything in D. 7 D has less overhead than Python (the reason why we use D from Python). 8 9 Error Handling: 10 11 D function should raise exception for python by PyErr_SetString(PyObject* type, const char* message) 12 The type can be PyExc_RuntimeError, PyExc_TypeError, etc 13 see also https://docs.python.org/3/c-api/exceptions.html#standard-exceptions 14 */ 15 16 private import deimos.python.Python : PyMethodDef, METH_VARARGS; 17 private import mir.pybind.conv : toPyFunction; 18 19 /// template to define python function (wrapper of PyMethodDef) 20 /// TODO insert type signature and args in docstring automatically 21 enum def(alias dfunc, string doc = "", string name = __traits(identifier, dfunc)) 22 = PyMethodDef(name, &toPyFunction!dfunc, METH_VARARGS, doc); 23 24 /// template to define python module (wrapper of PyModuleDef) 25 mixin template defModule(string modName, string modDoc, PyMethodDef[] defs) 26 { 27 private import deimos.python.Python : PyModuleDef, PyModuleDef_Base, PyMethodDef; 28 private import std..string : replace; 29 30 extern (C): 31 enum PyModuleDef_Base PyModuleDef_HEAD_INIT = {{1, null}, null, 0, null}; 32 33 enum PyMethodDef PyMethodDef_SENTINEL = {null, null, 0, null}; 34 35 void rtAtExit() 36 { 37 import core.runtime : rt_term; 38 rt_term(); 39 } 40 41 extern(D) static PyModuleDef mod = {PyModuleDef_HEAD_INIT, m_name: modName, m_doc: modDoc, m_size: -1}; 42 extern(D) static methods = defs ~ [PyMethodDef_SENTINEL]; 43 44 mixin( 45 q{ 46 pragma(mangle, __traits(identifier, PyInit_$)) 47 auto PyInit_$() 48 { 49 import deimos.python.Python : Py_AtExit, PyModule_Create; 50 import core.runtime : rt_init; 51 rt_init(); 52 Py_AtExit(&rtAtExit); 53 mod.m_methods = methods.ptr; 54 // TODO import_array(); // enable numpy API 55 return PyModule_Create(&mod); 56 } 57 }.replace("$", modName)); 58 }