1 // Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
2 // Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
3 // other details. No copyright assignment is required to contribute to Conduit.
4 
5 
6 //-----------------------------------------------------------------------------
7 // -- Python includes (these must be included first) --
8 //-----------------------------------------------------------------------------
9 #include <Python.h>
10 #include <structmember.h>
11 #include "bytesobject.h"
12 
13 #if PY_MAJOR_VERSION >= 3
14 #define IS_PY3K
15 #endif
16 
17 // use  proper strdup
18 #ifdef CONDUIT_PLATFORM_WINDOWS
19     #define _conduit_strdup _strdup
20 #else
21     #define _conduit_strdup strdup
22 #endif
23 
24 //-----------------------------------------------------------------------------
25 // -- standard lib includes --
26 //-----------------------------------------------------------------------------
27 #include <iostream>
28 #include <vector>
29 
30 //---------------------------------------------------------------------------//
31 // conduit includes
32 //---------------------------------------------------------------------------//
33 #include "conduit.hpp"
34 #include "conduit_relay.hpp"
35 #include "conduit_relay_python_exports.h"
36 
37 // conduit python module capi header
38 #include "conduit_python.hpp"
39 
40 using namespace conduit;
41 
42 //---------------------------------------------------------------------------//
43 // conduit::relay::about
44 //---------------------------------------------------------------------------//
45 static PyObject *
PyRelay_about()46 PyRelay_about()
47 {
48     //create and return a node with the result of about
49     PyObject *py_node_res = PyConduit_Node_Python_Create();
50     Node *node = PyConduit_Node_Get_Node_Ptr(py_node_res);
51     conduit::relay::about(*node);
52     return (PyObject*)py_node_res;
53 }
54 
55 //---------------------------------------------------------------------------//
56 // Python Module Method Defs
57 //---------------------------------------------------------------------------//
58 static PyMethodDef relay_python_funcs[] =
59 {
60     //-----------------------------------------------------------------------//
61     {"about",
62      (PyCFunction)PyRelay_about,
63       METH_NOARGS,
64       NULL},
65     //-----------------------------------------------------------------------//
66     // end relay methods table
67     //-----------------------------------------------------------------------//
68     {NULL, NULL, METH_VARARGS, NULL}
69 };
70 
71 //---------------------------------------------------------------------------//
72 //---------------------------------------------------------------------------//
73 // Module Init Code
74 //---------------------------------------------------------------------------//
75 //---------------------------------------------------------------------------//
76 
77 struct module_state {
78     PyObject *error;
79 };
80 
81 //---------------------------------------------------------------------------//
82 #if defined(IS_PY3K)
83 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
84 #else
85 #define GETSTATE(m) (&_state)
86 static struct module_state _state;
87 #endif
88 //---------------------------------------------------------------------------//
89 
90 //---------------------------------------------------------------------------//
91 // Extra Module Setup Logic for Python3
92 //---------------------------------------------------------------------------//
93 #if defined(IS_PY3K)
94 //---------------------------------------------------------------------------//
95 static int
relay_python_traverse(PyObject * m,visitproc visit,void * arg)96 relay_python_traverse(PyObject *m, visitproc visit, void *arg)
97 {
98     Py_VISIT(GETSTATE(m)->error);
99     return 0;
100 }
101 
102 //---------------------------------------------------------------------------//
103 static int
relay_python_clear(PyObject * m)104 relay_python_clear(PyObject *m)
105 {
106     Py_CLEAR(GETSTATE(m)->error);
107     return 0;
108 }
109 
110 //---------------------------------------------------------------------------//
111 static struct PyModuleDef relay_python_module_def =
112 {
113         PyModuleDef_HEAD_INIT,
114         "relay_python",
115         NULL,
116         sizeof(struct module_state),
117         relay_python_funcs,
118         NULL,
119         relay_python_traverse,
120         relay_python_clear,
121         NULL
122 };
123 
124 
125 #endif
126 
127 //---------------------------------------------------------------------------//
128 // The module init function signature is different between py2 and py3
129 // This macro simplifies the process of returning when an init error occurs.
130 //---------------------------------------------------------------------------//
131 #if defined(IS_PY3K)
132 #define PY_MODULE_INIT_RETURN_ERROR return NULL
133 #else
134 #define PY_MODULE_INIT_RETURN_ERROR return
135 #endif
136 //---------------------------------------------------------------------------//
137 
138 
139 //---------------------------------------------------------------------------//
140 // Main entry point
141 //---------------------------------------------------------------------------//
142 extern "C"
143 //---------------------------------------------------------------------------//
144 #if defined(IS_PY3K)
PyInit_conduit_relay_python(void)145 CONDUIT_RELAY_PYTHON_API PyObject * PyInit_conduit_relay_python(void)
146 #else
147 CONDUIT_RELAY_PYTHON_API void initconduit_relay_python(void)
148 #endif
149 //---------------------------------------------------------------------------//
150 {
151     //-----------------------------------------------------------------------//
152     // create our main module
153     //-----------------------------------------------------------------------//
154 
155 #if defined(IS_PY3K)
156     PyObject *relay_module = PyModule_Create(&relay_python_module_def);
157 #else
158     PyObject *relay_module = Py_InitModule((char*)"conduit_relay_python",
159                                              relay_python_funcs);
160 #endif
161 
162 
163     if(relay_module == NULL)
164     {
165         PY_MODULE_INIT_RETURN_ERROR;
166     }
167 
168     struct module_state *st = GETSTATE(relay_module);
169 
170     st->error = PyErr_NewException((char*)"conduit_relay_python.Error",
171                                    NULL,
172                                    NULL);
173     if (st->error == NULL)
174     {
175         Py_DECREF(relay_module);
176         PY_MODULE_INIT_RETURN_ERROR;
177     }
178 
179     // setup for conduit python c api
180     if(import_conduit() < 0)
181     {
182         PY_MODULE_INIT_RETURN_ERROR;
183     }
184 
185 
186 #if defined(IS_PY3K)
187     return relay_module;
188 #endif
189 
190 }
191 
192