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 }