1 deprecated("Use deimos.python instead. mir.pybind.pyapi will be removed in the next release.") 2 module mir.pybind.pyapi; 3 import core.stdc.config : c_long, c_ulong; 4 5 // pragma(mangle, __traits(identifier, PyObject)); 6 extern (C) { 7 struct PyTypeObject; 8 alias Py_ssize_t = ptrdiff_t; 9 10 struct PyObject 11 { 12 version (Py_DEBUG) { 13 PyObject*_ob_next; 14 PyObject*_ob_prev; 15 } 16 Py_ssize_t ob_refcnt; 17 PyTypeObject *ob_type; 18 } 19 } 20 21 version (unittest) {} else { 22 extern (C) { 23 alias PyCFunction = PyObject* function(PyObject*, PyObject*); 24 struct PyMethodDef { 25 const char *ml_name; /* The name of the built-in function/method */ 26 PyCFunction ml_meth; /* The C function that implements it */ 27 int ml_flags; /* Combination of METH_xxx flags, which mostly 28 describe the args expected by the C func */ 29 const char *ml_doc; /* The __doc__ attribute, or NULL */ 30 }; 31 32 // https://docs.python.org/3/c-api/module.html#c.PyModuleDef 33 alias inquiry = int function(PyObject*); 34 alias visitproc = int function(PyObject*, void*); 35 alias traverseproc = int function(PyObject*, visitproc, void*); 36 alias freefunc = void function(void*); 37 38 struct PyModuleDef_Base { 39 // PyObject_HEAD 40 PyObject ob_base; 41 PyObject* function() m_init; 42 Py_ssize_t m_index; 43 PyObject* m_copy; 44 } 45 46 struct PyModuleDef_Slot{ 47 int slot; 48 void *value; 49 } 50 51 struct PyModuleDef{ 52 PyModuleDef_Base m_base; 53 const char* m_name; 54 const char* m_doc; 55 Py_ssize_t m_size; 56 PyMethodDef *m_methods; 57 PyModuleDef_Slot* m_slots; 58 traverseproc m_traverse; 59 inquiry m_clear; 60 freefunc m_free; 61 } 62 63 /* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of 64 Python 3, it will stay at the value of 3; changes to the limited API 65 must be performed in a strictly backwards-compatible manner. */ 66 enum PYTHON_ABI_VERSION = 3; 67 68 PyObject* PyModule_Create2(PyModuleDef* def, int apiver); 69 PyObject* PyModule_Create(PyModuleDef* def) { 70 return PyModule_Create2(def, PYTHON_ABI_VERSION); 71 } 72 73 /// for format string, see https://docs.python.org/3/c-api/arg.html#strings-and-buffers 74 int PyArg_ParseTuple(PyObject *args, const char *format, ...); 75 76 enum PyModuleDef_Base PyModuleDef_HEAD_INIT = {{1, null}, null, 0, null}; 77 78 enum PyMethodDef PyMethodDef_SENTINEL = {null, null, 0, null}; 79 80 /* Flag passed to newmethodobject */ 81 enum : int { 82 /* #define METH_OLDARGS 0x0000 -- unsupported now */ 83 METH_VARARGS = 0x0001, 84 METH_KEYWORDS = 0x0002, 85 /* METH_NOARGS and METH_O must not be combined with the flags above. */ 86 METH_NOARGS = 0x0004, 87 METH_O = 0x0008, 88 /* METH_CLASS and METH_STATIC are a little different; these control 89 the construction of methods for a class. These cannot be used for 90 functions in modules. */ 91 METH_CLASS = 0x0010, 92 METH_STATIC = 0x0020 93 } 94 95 int Py_AtExit(void function()); 96 97 void rtAtExit() { 98 import core.runtime : rt_term; 99 rt_term(); 100 } 101 102 103 /** 104 Basic types 105 */ 106 double PyFloat_AsDouble(PyObject* pyfloat); 107 c_long PyLong_AsLong(PyObject *obj); 108 long PyLong_AsLongLong(PyObject *obj); 109 c_ulong PyLong_AsUnsignedLong(PyObject *pylong); 110 ulong PyLong_AsUnsignedLongLong(PyObject *pylong); 111 Py_ssize_t PyLong_AsSsize_t(PyObject *pylong); 112 size_t PyLong_AsSize_t(PyObject *pylong); 113 int PyObject_IsTrue(PyObject *o); 114 const(char*) PyUnicode_AsUTF8(PyObject *unicode); 115 116 extern __gshared PyObject* Py_True; 117 extern __gshared PyObject* Py_False; 118 119 PyObject* PyFloat_FromDouble(double); 120 PyObject* PyLong_FromLongLong(long); 121 PyObject* PyLong_FromUnsignedLongLong(ulong); 122 PyObject* PyLong_FromSize_t(size_t); 123 PyObject* PyLong_FromSsize_t(ptrdiff_t); 124 PyObject* PyBool_FromLong(long v); 125 PyObject* PyUnicode_FromStringAndSize(const(char*) u, Py_ssize_t len); 126 PyObject* PyTuple_New(Py_ssize_t); 127 int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o); 128 129 /** 130 Error handling 131 */ 132 void PyErr_Print(); 133 PyObject* PyErr_Occurred(); 134 void PyErr_SetString(PyObject* type, const char* message); 135 // NOTE: c globals need __gshared https://dlang.org/spec/interfaceToC.html#c-globals 136 extern __gshared PyObject* PyExc_TypeError; 137 extern __gshared PyObject* PyExc_RuntimeError; 138 extern __gshared PyObject* PyExc_ImportError; 139 extern __gshared PyObject* PyExc_AttributeError; 140 extern __gshared PyObject* PyExc_ValueError; 141 142 /** 143 Buffer Protocol 144 */ 145 import mir.ndslice.connect.cpython : Py_buffer; 146 int PyObject_GetBuffer(PyObject *exporter, Py_buffer *view, int flags); 147 int PyObject_CheckReadBuffer(PyObject *obj); 148 void PyBuffer_Release(Py_buffer *view); 149 PyObject* PyMemoryView_FromBuffer(Py_buffer *view); 150 /** 151 numpy API 152 */ 153 static __gshared void** PyArray_API; 154 PyObject* PyImport_ImportModule(const(char*)); 155 PyObject* PyObject_GetAttrString(PyObject*, const(char*)); 156 void* PyCapsule_GetPointer(PyObject *capsule, const(char*) name); 157 158 // from __multiarray_api.h 159 static int _import_array() 160 { 161 int st; 162 PyObject *numpy = PyImport_ImportModule("numpy.core.multiarray"); 163 PyObject *c_api; 164 165 if (numpy == null) { 166 PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); 167 return -1; 168 } 169 c_api = PyObject_GetAttrString(numpy, "_ARRAY_API"); 170 Py_DecRef(numpy); 171 if (c_api == null) { 172 PyErr_SetString(PyExc_AttributeError, "_ARRAY_API not found"); 173 return -1; 174 } 175 // if (!PyCapsule_CheckExact(c_api)) { 176 // PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is not PyCapsule object"); 177 // Py_DecRef(c_api); 178 // return -1; 179 // } 180 PyArray_API = cast(void**) PyCapsule_GetPointer(c_api, null); 181 Py_DecRef(c_api); 182 if (PyArray_API == null) { 183 PyErr_SetString(PyExc_RuntimeError, "_ARRAY_API is NULL pointer"); 184 return -1; 185 } 186 return 0; 187 } 188 189 //// This function must be called in the initialization section of a module that will make use of the C-API 190 void import_array() { 191 if (_import_array() < 0) { 192 PyErr_Print(); 193 PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import"); 194 // return NUMPY_IMPORT_ARRAY_RETVAL; 195 } 196 } 197 alias npy_intp = ptrdiff_t; 198 PyObject* PyArray_SimpleNew(int nd, npy_intp* dims, int typenum); 199 200 /// https://github.com/numpy/numpy/blob/v1.15.4/numpy/core/include/numpy/ndarraytypes.h#L65-L89 201 202 /// misc 203 extern __gshared PyObject _Py_NoneStruct; 204 void Py_IncRef(PyObject*); 205 void Py_DecRef(PyObject*); 206 207 PyObject* newNone() { 208 Py_IncRef(&_Py_NoneStruct); 209 return &_Py_NoneStruct; 210 } 211 212 } 213 }