Salome HOME
Porting to Mandrake 10.1 and new products:
[modules/kernel.git] / src / SALOMEGUI / PyInterp_base.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  CEA/DEN, EDF R&D
4 //
5 //
6 //
7 //  File   : PyInterp_base.cxx
8 //  Author : Christian CAREMOLI, Paul RASCLE, EDF
9 //  Module : SALOME
10 //  $Header$
11
12
13 #include <string>
14 #include <vector>
15
16 #include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)!
17 #include <cStringIO.h>
18
19 #include <qmutex.h>
20
21 #include "utilities.h"
22
23
24 using namespace std;
25
26
27 #ifdef _DEBUG_
28 static int MYDEBUG = 0;
29 static int MYPYDEBUG = 0;
30 #else
31 static int MYDEBUG = 0;
32 static int MYPYDEBUG = 0;
33 #endif
34
35
36 static QMutex myMutex(true);
37
38
39 PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): 
40   myThreadState(theThreadState),
41   mySaveThreadState(PyInterp_base::_gtstate)
42 {
43   PyEval_AcquireLock();
44   mySaveThreadState = PyThreadState_Swap(myThreadState); // store previous current in save,
45                                                          // set local in current
46 }
47
48
49 PyLockWrapper::~PyLockWrapper(){
50   PyThreadState_Swap(mySaveThreadState); // restore previous current (no need to get local,
51   PyEval_ReleaseLock();                  // local thread state* already in _tstate
52 }
53
54
55 ThreadLock::ThreadLock(QMutex* theMutex, const char* theComment):
56   myMutex(theMutex),
57   myComment(theComment)
58 {
59   if(MYDEBUG && myComment != "") MESSAGE(" ThreadLock "<<this<<"::"<<myMutex<<" - "<<myComment<<" - "<<myMutex->locked());
60   myMutex->lock();
61 }
62
63
64 ThreadLock::~ThreadLock(){
65   if(MYDEBUG && myComment != "") MESSAGE("~ThreadLock "<<this<<"::"<<myMutex<<" - "<<myComment);
66   myMutex->unlock();
67 }
68
69
70 bool IsPyLocked(){
71   return myMutex.locked();
72 }
73
74
75 ThreadLock GetPyThreadLock(const char* theComment){
76   return ThreadLock(&myMutex,theComment);
77 }
78
79
80 class PyReleaseLock{
81 public:
82   ~PyReleaseLock(){
83     if(MYPYDEBUG) MESSAGE("~PyReleaseLock()");
84     PyEval_ReleaseLock();
85   }
86 };
87
88
89 PyLockWrapper PyInterp_base::GetLockWrapper(){
90   return _tstate;
91 }
92
93
94 // main python interpreter
95
96 PyThreadState *PyInterp_base::_gtstate = 0; // force 0 before execution
97 int PyInterp_base::_argc = 1;
98 char* PyInterp_base::_argv[] = {""};
99
100 PyObject *PyInterp_base::builtinmodule = NULL;
101 PyObject *PyInterp_base::salome_shared_modules_module = NULL;
102
103
104 /*!
105  * basic constructor here : herited classes constructors must call initalize() method
106  * defined here.
107  */
108 PyInterp_base::PyInterp_base(): _tstate(0), _vout(0), _verr(0), _g(0), _atFirst(true)
109 {
110   if(MYPYDEBUG) MESSAGE("PyInterp_base::PyInterp_base() - this = "<<this);
111 }
112
113 PyInterp_base::~PyInterp_base()
114 {
115   if(MYPYDEBUG) MESSAGE("PyInterp_base::~PyInterp_base() - this = "<<this);
116   PyLockWrapper aLock(_tstate);
117   //Py_EndInterpreter(_tstate);
118 }
119
120
121 /*!
122  * Must be called by herited classes constructors. initialize() calls virtuals methods
123  * initstate & initcontext, not defined here in base class. initstate & initcontext methods
124  * must be implemented in herited classes, following the Python interpreter policy
125  * (mono or multi interpreter...).
126  */
127 void PyInterp_base::initialize()
128 {
129   _history.clear();       // start a new list of user's commands 
130   _ith = _history.begin();
131
132   if(!_gtstate) init_python();
133   // Here the global lock is released
134   if(MYPYDEBUG) MESSAGE("PyInterp_base::initialize() - this = "<<this<<"; _gtstate = "<<_gtstate);
135
136   // The lock will be acquired in initState. Make provision to release it on exit
137   PyReleaseLock aReleaseLock;
138
139   initState();
140   initContext();
141
142   // used to interpret & compile commands
143   PyObjWrapper m(PyImport_ImportModule("codeop"));
144   if(!m){
145     INFOS("PyInterp_base::initialize() - PyImport_ImportModule('codeop') failed");
146     PyErr_Print();
147     ASSERT(0);
148     return;
149   }   
150   
151   // Create cStringIO to capture stdout and stderr
152   PycString_IMPORT;
153   //PycStringIO = (PycStringIO_CAPI *)xxxPyCObject_Import("cStringIO", "cStringIO_CAPI");
154   _vout = PycStringIO->NewOutput(128);
155   _verr = PycStringIO->NewOutput(128);
156   
157   // All the initRun outputs are redirected to the standard output (console)
158   initRun();
159 }
160
161 void PyInterp_base::init_python()
162 {
163   /*
164    * Initialize the main state (_gtstate) if not already done
165    * The lock is released on init_python output
166    * It is the caller responsability to acquire it if needed
167    */
168   if(!_gtstate){
169     PyReleaseLock aReleaseLock;
170     Py_Initialize(); // Initialize the interpreter
171     PyEval_InitThreads(); // Initialize and acquire the global interpreter lock
172     PySys_SetArgv(_argc,_argv); // initialize sys.argv
173     _gtstate = PyThreadState_Get();
174     /*
175      * salome_shared_modules should be imported only once
176      */
177     salome_shared_modules_module = PyImport_ImportModule("salome_shared_modules");
178     if(!salome_shared_modules_module)
179       {
180         INFOS("PyInterp_base::initialize() - salome_shared_modules_module == NULL");
181         PyErr_Print();
182         PyErr_Clear();
183       }
184   }
185 }
186
187 string PyInterp_base::getbanner()
188 {
189   string aBanner("Python ");
190   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
191   aBanner = aBanner + "\ntype help to get general information on environment\n";
192   return aBanner;
193 }
194
195
196 int PyInterp_base::initRun()
197 {
198   PySys_SetObject("stderr",_verr);
199   PySys_SetObject("stdout",_vout);
200
201   PyObjWrapper verr(PyObject_CallMethod(_verr,"reset",""));
202   PyObjWrapper vout(PyObject_CallMethod(_vout,"reset",""));
203
204   //PyObject *m = PyImport_GetModuleDict();
205   
206   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
207   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
208
209   if(MYPYDEBUG) MESSAGE("PyInterp_base::initRun() - this = "<<this<<"; _verr = "<<_verr<<"; _vout = "<<_vout);
210   return 0;
211 }
212
213
214 /*!
215  * This function compiles a string (command) and then evaluates it in the dictionnary
216  * context if possible.
217  * Returns :
218  * -1 : fatal error 
219  *  1 : incomplete text
220  *  0 : complete text executed with success
221  */
222 int compile_command(const char *command,PyObject *context)
223 {
224   PyObject *m = PyImport_AddModule("codeop");
225   if(!m){ // Fatal error. No way to go on.
226     PyErr_Print();
227     return -1;
228   }
229   PyObjWrapper v(PyObject_CallMethod(m,"compile_command","s",command));
230   if(!v){
231     // Error encountered. It should be SyntaxError,
232     //so we don't write out traceback
233     PyObjWrapper exception, value, tb;
234     PyErr_Fetch(&exception, &value, &tb);
235     PyErr_NormalizeException(&exception, &value, &tb);
236     PyErr_Display(exception, value, NULL);
237     return -1;
238   }else if (v == Py_None){
239     // Incomplete text we return 1 : we need a complete text to execute
240     return 1;
241   }else{
242     // Complete and correct text. We evaluate it.
243     PyObjWrapper r(PyEval_EvalCode(v,context,context));
244     if(!r){
245       // Execution error. We return -1
246       PyErr_Print();
247       return -1;
248     }
249     // The command has been successfully executed. Return 0
250     return 0;
251   }
252 }
253
254
255 int PyInterp_base::run(const char *command)
256 {
257   if(_atFirst){
258     int ret = 0;
259     ret = simpleRun("from Help import *");
260     if (ret) { 
261       _atFirst = false;
262       return ret;
263     }
264     ret = simpleRun("import salome");
265     if (ret) { 
266       _atFirst = false;
267       return ret;
268     }
269     ret = simpleRun("salome.salome_init()");
270     if (ret) { 
271       _atFirst = false;
272       return ret;
273     }
274     _atFirst = false;
275   }
276   return simpleRun(command);
277 }
278
279
280 int PyInterp_base::simpleRun(const char *command)
281 {
282   if( !_atFirst && strcmp(command,"") != 0 ) {
283     _history.push_back(command);
284     _ith = _history.end();
285   }
286
287   // We come from C++ to enter Python world
288   // We need to acquire the Python global lock
289   PyLockWrapper aLock(_tstate);
290
291   // Reset redirected outputs before treatment
292   PySys_SetObject("stderr",_verr);
293   PySys_SetObject("stdout",_vout);
294     
295   PyObjWrapper verr(PyObject_CallMethod(_verr,"reset",""));
296   PyObjWrapper vout(PyObject_CallMethod(_vout,"reset",""));
297   
298   int ier = compile_command(command,_g);
299
300   // Outputs are redirected on standards outputs (console)
301   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
302   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
303   return ier;
304 }
305
306
307 const char * PyInterp_base::getPrevious()
308 {
309   if(_ith != _history.begin()){
310     _ith--;
311     return (*_ith).c_str();
312   }
313   else
314     return BEGIN_HISTORY_PY;
315 }
316
317
318 const char * PyInterp_base::getNext()
319 {
320   if(_ith != _history.end()){
321     _ith++;
322   }
323   if (_ith == _history.end())
324     return TOP_HISTORY_PY;
325   else
326     return (*_ith).c_str();
327 }
328
329
330 string PyInterp_base::getverr(){ 
331   PyLockWrapper aLock(_tstate);
332   PyObjWrapper v(PycStringIO->cgetvalue(_verr));
333   string aRet(PyString_AsString(v));
334   return aRet;
335 }
336
337
338 string PyInterp_base::getvout(){  
339   PyLockWrapper aLock(_tstate);
340   PyObjWrapper v(PycStringIO->cgetvalue(_vout));
341   string aRet(PyString_AsString(v));
342   return aRet;
343 }
344