1 /***************************************************************************
2 gdlpython.cpp - python embedded in GDL
3 -------------------
4 begin : July 22 2002
5 copyright : (C) 2002 by Marc Schellens
6 email : m_schellens@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #ifdef INCLUDE_GDLPYTHON_CPP
19
20 //#include "includefirst.hpp"
21
22 // this part contains variable conversion stuff
23 // used by both GDL embedded in python and python embedded in GDL
24
25 #if defined(USE_PYTHON) || defined(PYTHON_MODULE)
26 #include <numpy/arrayobject.h>
27
28 //#include <deque>
29 //#include <iterator>
30
31 //#include "datatypes.hpp"
32 //#include "envt.hpp"
33 //#include "objects.hpp"
34
35 using namespace std;
36
37 #if PY_MAJOR_VERSION >= 3
38 #include <cstddef>
PythonInit()39 std::nullptr_t PythonInit()
40 {
41 if( Py_IsInitialized()) return 0;
42 #else
43 void PythonInit()
44 {
45 if( Py_IsInitialized()) return;
46 #endif
47 Py_Initialize(); // signal handlers?
48
49 static int argc = 1;
50 #if PY_MAJOR_VERSION >= 3
51 static wchar_t* arg0 = Py_DecodeLocale("./py/python.exe",NULL);
52 static wchar_t* argv[] = {arg0};
53 #else
54 static char* arg0 = (char*)"./py/python.exe";
55 static char* argv[] = {arg0};
56 #endif
57 PySys_SetArgv(argc, argv);
58
59 // http://docs.scipy.org/doc/numpy/reference/c-api.array.html#miscellaneous
60 import_array();
61 #if PY_MAJOR_VERSION >= 3
62 return 0;
63 #endif
64 }
65
66 void PythonEnd()
67 {
68 // was not possible with numarray (numarray cannot be restarted)
69 // but now we use Numpy??? (TODO/FIXME)
70
71 //if( !Py_IsInitialized()) return;
72 //Py_Finalize();
73 }
74
75 template< typename T>
76 T* NewFromPyArrayObject( const dimension& dim, PyArrayObject *array)
77 {
78 T* res = new T( dim, BaseGDL::NOZERO);
79 SizeT nEl = res->N_Elements();
80 typename T::Ty* dPtr =
81 reinterpret_cast<typename T::Ty*>( PyArray_DATA(array));
82 for( SizeT i=0; i<nEl; ++i) (*res)[i] = dPtr[i];
83 Py_DECREF(array); // must be decremented
84 return res;
85 }
86
87 BaseGDL* FromPython( PyObject* pyObj)
88 {
89 if( !PyArray_Check( pyObj))
90 {
91 #if PY_MAJOR_VERSION >= 3
92 if( PyUnicode_Check( pyObj))
93 {
94 return new DStringGDL( PyUnicode_AsUTF8( pyObj));
95 }
96 #else
97 if( PyString_Check( pyObj))
98 {
99 return new DStringGDL( PyString_AsString( pyObj));
100 }
101 if( PyInt_Check( pyObj))
102 {
103 return new DLongGDL( PyInt_AsLong( pyObj));
104 }
105 #endif
106 if( PyLong_Check( pyObj))
107 {
108 return new DLongGDL( PyLong_AsLong( pyObj));
109 }
110 if( PyFloat_Check( pyObj))
111 {
112 return new DDoubleGDL( PyFloat_AsDouble( pyObj));
113 }
114 if( PyComplex_Check( pyObj))
115 {
116 DDouble re,im;
117 re = PyComplex_RealAsDouble( pyObj);
118 im = PyComplex_ImagAsDouble( pyObj);
119 return new DComplexDblGDL( DComplexDbl( re, im));
120 }
121 throw GDLException( "Cannot convert python scalar.") ;
122 }
123
124 // make array contiguous
125 PyArrayObject* array = PyArray_GETCONTIGUOUS( reinterpret_cast< PyArrayObject *>( pyObj));
126
127 if( array == NULL)
128 throw GDLException( "Error getting python array.") ;
129
130 int nDim = PyArray_NDIM(array);
131 SizeT dimArr[ MAXRANK];
132 if( nDim > MAXRANK)
133 {
134 Warning( "Python array has more than "+MAXRANK_STR+
135 " dimensions. Extending last one.");
136 SizeT lastDim = PyArray_DIM(array, MAXRANK-1);
137 for( SizeT i=MAXRANK; i<nDim; ++i) lastDim *= PyArray_DIM(array, i);
138 for( SizeT i=0; i<MAXRANK-1; ++i)
139 dimArr[ i] = PyArray_DIM(array, i);
140 dimArr[ MAXRANK-1] = lastDim;
141 nDim = MAXRANK;
142 }
143 else
144 {
145 for( SizeT i=0; i<nDim; ++i)
146 dimArr[ i] = PyArray_DIM(array, i);
147 }
148 dimension dim( dimArr, nDim);
149
150 switch( PyArray_DTYPE(array)->type_num)
151 {
152 case NPY_UINT8: //GDL_BYTE
153 return NewFromPyArrayObject< DByteGDL>( dim, array);
154 case NPY_INT16: //GDL_INT
155 return NewFromPyArrayObject< DIntGDL>( dim, array);
156 case NPY_INT32: //GDL_LONG
157 return NewFromPyArrayObject< DLongGDL>( dim, array);
158 case NPY_FLOAT32: //GDL_FLOAT
159 return NewFromPyArrayObject< DFloatGDL>( dim, array);
160 case NPY_FLOAT64: //GDL_DOUBLE
161 return NewFromPyArrayObject< DDoubleGDL>( dim, array);
162 case NPY_COMPLEX64: //GDL_COMPLEX
163 return NewFromPyArrayObject< DComplexGDL>( dim, array);
164 case NPY_COMPLEX128: //GDL_COMPLEXDBL
165 return NewFromPyArrayObject< DComplexDblGDL>( dim, array);
166 case NPY_UINT16: //GDL_UINT*
167 return NewFromPyArrayObject< DUIntGDL>( dim, array);
168 case NPY_UINT32: //GDL_ULONG*
169 return NewFromPyArrayObject< DULongGDL>( dim, array);
170 default:
171 Py_DECREF(array); // must be decremented
172 throw GDLException( "FromPython: Unknown array type.") ;
173 }
174
175 return NULL; // compiler shut-up
176 }
177
178 // you can compile GDL as a python module without supporting
179 // python *within* GDL
180 #ifdef USE_PYTHON
181
182 namespace lib {
183
184 using namespace std;
185
186 BaseGDL* gdlpython( EnvT* e, int kIx)
187 {
188 PythonInit();
189
190 SizeT nParam = e->NParam();
191
192 static int argvIx = e->KeywordIx( "ARGV");
193 BaseGDL* argv1 = e->GetKW( argvIx);
194 if( argv1 != NULL)
195 {
196 DStringGDL* argvS = dynamic_cast<DStringGDL*>( argv1);
197 if( argvS == NULL)
198 e->Throw( "ARGV keyword must be of type STRING.");
199
200 int argc = argvS->N_Elements();
201 #if PY_MAJOR_VERSION >= 3
202 wchar_t** argv = new wchar_t*[ argc];
203 #else
204 char** argv = new char*[ argc];
205 #endif
206
207 // python copies the value -> treats it as const
208 for( int i=0; i<argc; ++i)
209 #if PY_MAJOR_VERSION >= 3
210 argv[i] = Py_DecodeLocale(const_cast<char*>((*argvS)[ i].c_str()), NULL);
211 #else
212 argv[i] = const_cast<char*>((*argvS)[ i].c_str());
213 #endif
214
215 PySys_SetArgv(argc, argv);
216 delete[] argv;
217 }
218
219 if( nParam < 2 && kIx != -1)
220 e->Throw( "Function must have at least 2 parameters.");
221
222 if( nParam == 0)
223 return NULL; // ok, just keywords
224
225 DString module;
226 e->AssureScalarPar<DStringGDL>( 0, module);
227
228 // PyObject* pName = PyString_FromString( module.c_str());
229 // // Error checking of pName left out
230 // PyObject* pModule = PyImport_Import(pName);
231 // Py_DECREF(pName);
232 PyObject* pModule =
233 PyImport_ImportModule(const_cast<char*>(module.c_str()));
234 if (pModule == NULL)
235 {
236 PyErr_Print();
237 e->Throw( "Failed to load module: "+module);
238 }
239
240 if( nParam == 1)
241 {
242 Py_DECREF(pModule);
243 return NULL; // ok, only load module
244 }
245
246 DString function;
247 e->AssureScalarPar<DStringGDL>( 1, function);
248
249 PyObject* pDict = PyModule_GetDict(pModule);
250 /* pDict is a borrowed reference */
251
252 PyObject* pFunc = PyDict_GetItemString(pDict, function.c_str());
253 /* pFunc: Borrowed reference */
254
255 if( !(pFunc && PyCallable_Check(pFunc)))
256 {
257 if (PyErr_Occurred()) PyErr_Print();
258 e->Throw( "Cannot find function: "+function);
259 }
260
261 PyObject* pArgs = PyTuple_New( nParam-2);
262 for( SizeT i = 2; i<nParam; ++i)
263 {
264 BaseGDL* actPar = e->GetParDefined( i);
265 PyObject* pValue = actPar->ToPython();
266 if (!pValue)
267 {
268 Py_DECREF(pArgs);
269 Py_DECREF(pModule);
270
271 e->Throw( "Cannot convert value: "+
272 e->GetParString( i));
273 }
274 /* pValue reference stolen here: */
275 PyTuple_SetItem(pArgs, i-2, pValue);
276 }
277
278 PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
279 Py_DECREF(pArgs);
280 Py_DECREF(pModule);
281 // pDict and pFunc are borrowed and must not be Py_DECREF-ed
282 if( pResult == NULL)
283 {
284 PyErr_Print();
285 e->Throw( "Call failed: "+module+"."+function);
286 }
287
288 if( kIx == -1) // called as procedures
289 {
290 Py_DECREF(pResult);
291 return NULL;
292 }
293
294 // as function
295 BaseGDL* res;
296 if( pResult == Py_None)
297 {
298 Py_DECREF(pResult);
299 BaseGDL* defRet = e->GetKW( kIx);
300 if( defRet == NULL)
301 e->Throw( "Function returned 'None' "
302 "and DEFAULTRETURN not defined.");
303 res = defRet->Dup();
304 }
305 else
306 {
307 try {
308 res = FromPython( pResult);
309 Py_DECREF(pResult);
310 }
311 catch(...)
312 {
313 Py_DECREF(pResult);
314 throw;
315 }
316 }
317
318 return res;
319 }
320
321 // GDL PYTHON procedure
322 // PYTHON,module,function[,args]
323 void gdlpython_pro( EnvT* e)
324 {
325 gdlpython( e, -1);
326 }
327
328 // GDL PYTHON function
329 BaseGDL* gdlpython_fun( EnvT* e)
330 {
331 static int kIx = e->KeywordIx( "DEFAULTRETURNVALUE");
332 return gdlpython( e, kIx);
333 }
334
335
336 } // namespace
337
338
339 #endif // #ifdef USE_PYTHON
340
341 #endif // #if defined(USE_PYTHON) || defined(PYTHON_MODULE)
342
343 #endif // #ifdef INCLUDE_GDLPYTHON_CPP
344