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