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