Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / PyInterp / PyInterp_Interp.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  File   : PyInterp_Interp.cxx
24 //  Author : Christian CAREMOLI, Paul RASCLE, EDF
25 //  Module : SALOME
26 //
27 #include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
28 #include <pythread.h>
29
30 #include <cStringIO.h>
31 #include <structmember.h>
32
33 #include <string>
34 #include <vector>
35 #include <map>
36 #include <iostream>
37
38 #define TOP_HISTORY_PY   "--- top of history ---"
39 #define BEGIN_HISTORY_PY "--- begin of history ---"
40
41 // a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state)
42 std::map<long,PyThreadState*> currentThreadMap;
43
44 /*!
45   \class PyLockWrapper
46   \brief Python GIL wrapper.
47 */
48
49 /*!
50   \brief Constructor. Automatically acquires GIL.
51   \param theThreadState python thread state
52 */
53 PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): 
54   myThreadState(theThreadState),
55   mySaveThreadState(0)
56 {
57   if (myThreadState->interp == PyInterp_Interp::_interp)
58     _savestate = PyGILState_Ensure();
59   else
60     PyEval_AcquireThread(myThreadState);
61 }
62
63 /*!
64   \brief Destructor. Automatically releases GIL.
65 */
66 PyLockWrapper::~PyLockWrapper()
67 {
68   if (myThreadState->interp == PyInterp_Interp::_interp)
69     PyGILState_Release(_savestate);
70   else
71     PyEval_ReleaseThread(myThreadState);
72 }
73
74 /*!
75   \brief Get Python GIL wrapper.
76   \return GIL lock wrapper (GIL is automatically acquired here)
77 */
78 PyLockWrapper PyInterp_Interp::GetLockWrapper()
79 {
80   if (_tstate->interp == PyInterp_Interp::_interp)
81     return _tstate;
82
83   // If we are here, we have a secondary python interpreter. Try to get a thread state synchronized with the system thread
84   long currentThreadid=PyThread_get_thread_ident(); // the system thread id
85   PyThreadState* theThreadState;
86   if(currentThreadMap.count(currentThreadid) != 0)
87     {
88       //a thread state exists for this thread id
89       PyThreadState* oldThreadState=currentThreadMap[currentThreadid];
90       if(_tstate->interp ==oldThreadState->interp)
91         {
92           //The old thread state has the same python interpreter as this one : reuse the threadstate
93           theThreadState=oldThreadState;
94         }
95       else
96         {
97           //The old thread state has not the same python interpreter as this one : delete the old threadstate and create a new one
98           PyEval_AcquireLock();
99           PyThreadState_Clear(oldThreadState);
100           PyThreadState_Delete(oldThreadState);
101           PyEval_ReleaseLock();
102           theThreadState=PyThreadState_New(_tstate->interp);
103           currentThreadMap[currentThreadid]=theThreadState;
104         }
105     }
106   else
107     {
108       // no old thread state for this thread id : create a new one
109       theThreadState=PyThreadState_New(_tstate->interp);
110       currentThreadMap[currentThreadid]=theThreadState;
111     }
112   return theThreadState;
113 }
114
115 /*
116   The following functions are used to hook the Python 
117   interpreter output.
118 */
119
120 static void
121 PyStdOut_dealloc(PyStdOut *self)
122 {
123   PyObject_Del(self);
124 }
125
126 static PyObject*
127 PyStdOut_write(PyStdOut *self, PyObject *args)
128 {
129   char *c;
130   int l;
131   if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
132     return NULL;
133   if(self->_cb==NULL) {
134     if ( self->_iscerr )
135       std::cerr << c ;
136     else
137       std::cout << c ;
138   }
139   else {
140     self->_cb(self->_data,c);
141   }
142   Py_INCREF(Py_None);
143   return Py_None;
144 }
145
146 static PyObject*
147 PyStdOut_flush(PyStdOut *self)
148 {
149   Py_INCREF(Py_None);
150   return Py_None;
151 }
152
153 static PyMethodDef PyStdOut_methods[] = {
154   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
155   {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
156   {NULL,    NULL}   /* sentinel */
157 };
158
159 static PyMemberDef PyStdOut_memberlist[] = {
160   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
161    (char*)"flag indicating that a space needs to be printed; used by print"},
162   {NULL} /* Sentinel */
163 };
164
165 static PyTypeObject PyStdOut_Type = {
166   /* The ob_type field must be initialized in the module init function
167    * to be portable to Windows without using C++. */
168   PyObject_HEAD_INIT(NULL)
169   0,                            /*ob_size*/
170   "PyOut",                      /*tp_name*/
171   sizeof(PyStdOut),             /*tp_basicsize*/
172   0,                            /*tp_itemsize*/
173   /* methods */
174   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
175   0,                            /*tp_print*/
176   0,                            /*tp_getattr*/
177   0,                            /*tp_setattr*/
178   0,                            /*tp_compare*/
179   0,                            /*tp_repr*/
180   0,                            /*tp_as_number*/
181   0,                            /*tp_as_sequence*/
182   0,                            /*tp_as_mapping*/
183   0,                            /*tp_hash*/
184   0,                            /*tp_call*/
185   0,                            /*tp_str*/
186   PyObject_GenericGetAttr,      /*tp_getattro*/
187   /* softspace is writable:  we must supply tp_setattro */
188   PyObject_GenericSetAttr,      /* tp_setattro */
189   0,                            /*tp_as_buffer*/
190   Py_TPFLAGS_DEFAULT,           /*tp_flags*/
191   0,                            /*tp_doc*/
192   0,                            /*tp_traverse*/
193   0,                            /*tp_clear*/
194   0,                            /*tp_richcompare*/
195   0,                            /*tp_weaklistoffset*/
196   0,                            /*tp_iter*/
197   0,                            /*tp_iternext*/
198   PyStdOut_methods,             /*tp_methods*/
199   PyStdOut_memberlist,          /*tp_members*/
200   0,                            /*tp_getset*/
201   0,                            /*tp_base*/
202   0,                            /*tp_dict*/
203   0,                            /*tp_descr_get*/
204   0,                            /*tp_descr_set*/
205   0,                            /*tp_dictoffset*/
206   0,                            /*tp_init*/
207   0,                            /*tp_alloc*/
208   0,                            /*tp_new*/
209   0,                            /*tp_free*/
210   0,                            /*tp_is_gc*/
211 };
212
213 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
214
215 static PyStdOut* newPyStdOut( bool iscerr )
216 {
217   PyStdOut *self;
218   self = PyObject_New(PyStdOut, &PyStdOut_Type);
219   if (self == NULL)
220     return NULL;
221   self->softspace = 0;
222   self->_cb = NULL;
223   self->_iscerr = iscerr;
224   return self;
225 }
226
227 /*!
228   \class PyInterp_Interp
229   \brief Generic embedded Python interpreter.
230 */
231
232 int   PyInterp_Interp::_argc   = 1;
233 char* PyInterp_Interp::_argv[] = {(char*)""};
234 PyObject*           PyInterp_Interp::builtinmodule = NULL;
235 PyThreadState*      PyInterp_Interp::_gtstate      = NULL;
236 PyInterpreterState* PyInterp_Interp::_interp       = NULL;
237
238 /*!
239   \brief Basic constructor.
240   
241   After construction the interpreter instance successor classes 
242   must call virtual method initalize().
243 */
244 PyInterp_Interp::PyInterp_Interp(): 
245   _tstate(0), _vout(0), _verr(0), _g(0)
246 {
247 }
248
249 /*!
250   \brief Destructor.
251 */
252 PyInterp_Interp::~PyInterp_Interp()
253 {
254 }
255
256 /*!
257   \brief Initialize embedded interpreter.
258   
259   This method shoud be called after construction of the interpreter.
260   The method initialize() calls virtuals methods
261   - initPython()  to initialize global Python interpreter
262   - initState()   to initialize embedded interpreter state
263   - initContext() to initialize interpreter internal context
264   - initRun()     to prepare interpreter for running commands
265   which should be implemented in the successor classes, according to the
266   embedded Python interpreter policy (mono or multi interpreter, etc).
267 */
268 void PyInterp_Interp::initialize()
269 {
270   _history.clear();       // start a new list of user's commands 
271   _ith = _history.begin();
272
273   initPython();
274   // Here the global lock is released
275
276   initState();
277
278   PyEval_AcquireThread(_tstate);
279
280   initContext();
281
282   // used to interpret & compile commands
283   PyObjWrapper m(PyImport_ImportModule("codeop"));
284   if(!m) {
285     PyErr_Print();
286     PyEval_ReleaseThread(_tstate);
287     return;
288   }
289
290   // Create python objects to capture stdout and stderr
291   _vout=(PyObject*)newPyStdOut( false ); // stdout 
292   _verr=(PyObject*)newPyStdOut( true );  // stderr
293
294   // All the initRun outputs are redirected to the standard output (console)
295   initRun();
296   PyEval_ReleaseThread(_tstate);
297 }
298
299 /*!
300   \brief Initialize Python interpreter.
301
302   In case if Python is not initialized, it sets program name, initializes the interpreter, sets program arguments,
303   initializes threads. 
304   Otherwise, it just obtains the global interpreter and thread states. This is important for light SALOME configuration, 
305   as in full SALOME this is done at SalomeApp level.
306   \sa SalomeApp_PyInterp class
307  */
308 void PyInterp_Interp::initPython()
309 {
310   if (!Py_IsInitialized()){
311     // Python is not initialized
312     Py_SetProgramName(_argv[0]);
313     Py_Initialize(); // Initialize the interpreter
314     PySys_SetArgv(_argc, _argv);
315     PyEval_InitThreads(); // Create (and acquire) the interpreter lock
316   }
317
318   if ( _interp == NULL )
319     _interp = PyThreadState_Get()->interp;
320   if (PyType_Ready(&PyStdOut_Type) < 0) {
321     PyErr_Print();
322   }
323   if ( _gtstate == NULL )
324     _gtstate = PyEval_SaveThread(); // Release global thread state
325 }
326
327 /*!
328   \brief Get embedded Python interpreter banner.
329   \return banner string
330  */
331 std::string PyInterp_Interp::getbanner()
332 {
333  // Should we take the lock ?
334  // PyEval_RestoreThread(_tstate);
335   std::string aBanner("Python ");
336   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
337   aBanner = aBanner + "\ntype help to get general information on environment\n";
338   //PyEval_SaveThread();
339   return aBanner;
340 }
341
342 /*!
343   \brief Initialize run command.
344  
345   This method is used to prepare interpreter for running 
346   Python commands.
347   
348   \return \c true on success and \c false on error
349 */
350 bool PyInterp_Interp::initRun()
351 {
352   // 
353   // probably all below code isn't required
354   //
355   /*
356   PySys_SetObject("stderr",_verr);
357   PySys_SetObject("stdout",_vout);
358
359   //PyObject *m = PyImport_GetModuleDict();
360   
361   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
362   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
363   */
364   return true;
365 }
366
367 /*!
368   \brief Compile Python command and evaluate it in the 
369          python dictionary context if possible.
370   \internal
371   \param command Python command string
372   \param context Python context (dictionary)
373   \return -1 on fatal error, 1 if command is incomplete and 0
374          if command is executed successfully
375  */
376 static int compile_command(const char *command,PyObject *context)
377 {
378   PyObject *m = PyImport_AddModule("codeop");
379   if(!m) { // Fatal error. No way to go on.
380     PyErr_Print();
381     return -1;
382   }
383   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
384   if(!v) {
385     // Error encountered. It should be SyntaxError,
386     //so we don't write out traceback
387     PyObjWrapper exception, value, tb;
388     PyErr_Fetch(&exception, &value, &tb);
389     PyErr_NormalizeException(&exception, &value, &tb);
390     PyErr_Display(exception, value, NULL);
391     return -1;
392   }
393   else if (v == Py_None) {
394     // Incomplete text we return 1 : we need a complete text to execute
395     return 1;
396   }
397   else {
398     // Complete and correct text. We evaluate it.
399     //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
400     //    PyObjWrapper r(PyEval_EvalCode(v,context,context));
401     //#else
402     PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context));
403     //#endif
404     if(!r) {
405       // Execution error. We return -1
406       PyErr_Print();
407       return -1;
408     }
409     // The command has been successfully executed. Return 0
410     return 0;
411   }
412 }
413
414 /*!
415   \brief Run Python command.
416   \param command Python command
417   \return command status
418 */
419 int PyInterp_Interp::run(const char *command)
420 {
421   beforeRun();
422   return simpleRun(command);
423 }
424
425 /*!
426   \brief Run Python command (used internally).
427   \param command Python command
428   \param addToHistory if \c true (default), the command is added to the commands history
429   \return command status
430 */
431 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
432 {
433   if( addToHistory && strcmp(command,"") != 0 ) {
434     _history.push_back(command);
435     _ith = _history.end();
436   }
437
438   // We come from C++ to enter Python world
439   // We need to acquire the Python global lock
440   //PyLockWrapper aLock(_tstate); // san - lock is centralized now
441
442   // Reset redirected outputs before treatment
443   PySys_SetObject((char*)"stderr",_verr);
444   PySys_SetObject((char*)"stdout",_vout);
445
446   int ier = compile_command(command,_g);
447
448   // Outputs are redirected on standards outputs (console)
449   PySys_SetObject((char*)"stdout",PySys_GetObject((char*)"__stdout__"));
450   PySys_SetObject((char*)"stderr",PySys_GetObject((char*)"__stderr__"));
451
452   return ier;
453 }
454
455 /*!
456   \brief Get previous command in the commands history.
457   \return previous command
458 */
459 const char * PyInterp_Interp::getPrevious()
460 {
461   if(_ith != _history.begin()){
462     _ith--;
463     return (*_ith).c_str();
464   }
465   else
466     return BEGIN_HISTORY_PY;
467 }
468
469 /*!
470   \brief Get next command in the commands history.
471   \return next command
472 */
473 const char * PyInterp_Interp::getNext()
474 {
475   if(_ith != _history.end()){
476     _ith++;
477   }
478   if (_ith == _history.end())
479     return TOP_HISTORY_PY;
480   else
481     return (*_ith).c_str();
482 }
483
484 /*!
485   \brief Set Python standard output device hook.
486   \param cb callback function
487   \param data callback function parameters
488 */
489 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
490 {  
491   ((PyStdOut*)_vout)->_cb=cb;
492   ((PyStdOut*)_vout)->_data=data;
493 }
494
495 /*!
496   \brief Set Python standard error device hook.
497   \param cb callback function
498   \param data callback function parameters
499 */
500 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
501 {  
502   ((PyStdOut*)_verr)->_cb=cb;
503   ((PyStdOut*)_verr)->_data=data;
504 }