Salome HOME
This commit was generated by cvs2git to create tag 'V1_4_0b2'.
[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 using namespace std;
13 #include "PyInterp_base.h"
14 #include "utilities.h"
15 #include <string>
16 #include <vector>
17 #include <cStringIO.h>
18
19 using namespace std;
20
21 extern "C" PyObject * PyEval_EvalCode(PyObject *co, PyObject *g, PyObject *l);
22
23 static PyThreadState *savedThreadState = NULL;
24
25 /*!
26  * We have our own routines which are identical to the SIP routines
27  * to not depend from SIP software evolutions
28  */
29
30 extern "C" void salomeAcquireLock()
31 {
32   MESSAGE("salomeAcquireLock");
33   PyEval_RestoreThread(savedThreadState);
34   savedThreadState = NULL;
35 }
36
37 extern "C" void salomeReleaseLock()
38 {
39   MESSAGE("salomeReleaseLock");
40   savedThreadState = PyEval_SaveThread();
41 }
42
43 extern "C" int salomeCondAcquireLock()
44 {
45   MESSAGE("salomeCondAcquireLock");
46   if(savedThreadState != NULL)
47     {
48       /*
49        * If savedThreadState is not NULL, Python global lock is not already acquired
50        * We acquire it
51        * and return 1 to the caller
52        */
53       salomeAcquireLock();
54       //MESSAGE("We got it (the lock)");
55       return 1;
56     }
57   /*
58    * If savedThreadState is NULL, Python global lock is already acquired
59    * We don't acquire or release it
60    * We return 0 to the caller
61    * CAUTION : it's only true when there is no event programming running (Tkinter, PyQt)
62    */
63   return 0;
64 }
65
66 extern "C" void salomeCondReleaseLock(int rellock)
67 {
68   MESSAGE("salomeCondReleaseLock");
69   if(rellock )
70     salomeReleaseLock();
71 }
72
73 // main python interpreter
74
75 PyThreadState *PyInterp_base::_gtstate=0; // force 0 before execution
76 int PyInterp_base::_argc=1;
77 char* PyInterp_base::_argv[] = {""};
78
79 PyObject *PyInterp_base::builtinmodule=NULL;
80 PyObject *PyInterp_base::salome_shared_modules_module=NULL;
81
82 void init_python()
83 {
84   SCRUTE(PyInterp_base::_gtstate);
85   if (PyInterp_base::_gtstate) return;
86   Py_Initialize();               // Initialize the interpreter
87   PyEval_InitThreads();          // Create (and acquire) the interpreter lock
88   PySys_SetArgv(PyInterp_base::_argc,PyInterp_base::_argv);      // initialize sys.argv
89   PyInterp_base::_gtstate = PyThreadState_Get();
90   SCRUTE(PyInterp_base::_gtstate);
91
92   //   /*
93   //    * Import __builtin__ module and store it to use it with all sub-interpreters
94   //    * This hack could be used with event programming (PyQt) to avoid errors 
95   //    * encountered with incoherent builtins
96   //    */
97
98   //   PyInterp_base::builtinmodule =PyImport_ImportModule("__builtin__");
99   //   SCRUTE(PyInterp_base::builtinmodule->ob_refcnt);
100
101   /*
102    * Import salome_shared_modules module and store it to use it with all sub-interpreters
103    */
104
105   PyInterp_base::salome_shared_modules_module =PyImport_ImportModule("salome_shared_modules");
106   if(PyInterp_base::salome_shared_modules_module == NULL){
107       MESSAGE("init_python: problem with salome_shared_modules import");
108       PyErr_Print();
109       PyErr_Clear();
110       salomeReleaseLock();
111       return;
112   }
113   SCRUTE(PyInterp_base::salome_shared_modules_module->ob_refcnt);
114   salomeReleaseLock();
115 }
116
117 /*!
118  * This function compiles a string (command) and then evaluates it in the dictionnary
119  * context if possible.
120  * Returns :
121  * -1 : fatal error 
122  *  1 : incomplete text
123  *  0 : complete text executed with success
124  */
125
126 int compile_command(const char *command,PyObject *context)
127 {
128   SCRUTE(command);
129   PyObject *m,*v,*r;
130
131   m=PyImport_AddModule("codeop");
132   if(m == NULL)
133     {
134       /*
135        * Fatal error. No way to go on.
136        */
137       PyErr_Print();
138       return -1;
139     }
140   v= PyObject_CallMethod(m,"compile_command","s",command);
141   if (v == NULL)
142     {
143       /*
144        * Error encountered. It should be SyntaxError
145        * so we don't write out traceback
146        */
147       PyObject *exception,*value,*tb;
148       PyErr_Fetch(&exception, &value, &tb);
149       PyErr_NormalizeException(&exception, &value, &tb);
150       PyErr_Display(exception, value, NULL);
151       Py_XDECREF(exception);
152       Py_XDECREF(value);
153       Py_XDECREF(tb);
154
155       return -1;
156     }
157   else if (v == Py_None)
158     {
159       /*
160        *  Incomplete text we return 1 : we need a complete text to execute
161        */
162       return 1;
163     }
164   else
165     {
166       /*
167        * Complete and correct text. We evaluate it.
168        */
169       r  = PyEval_EvalCode(v,context,context);
170       Py_DECREF(v);
171       if (r==NULL)
172         {
173           /*
174            * Execution error. We return -1
175            */
176           PyErr_Print();
177           return -1;
178         }
179       Py_DECREF(r);
180       /*
181        * The command has been successfully executed. Return 0
182        */
183       return 0;
184     }
185 }
186
187 /*!
188  * basic constructor here : herited classes constructors must call initalize() method
189  * defined here.
190  */
191
192 PyInterp_base::PyInterp_base():_tstate(0),_vout(0),_verr(0),_g(0),_atFirst(true)
193 {
194   MESSAGE("PyInterp_base::PyInterp_base()");
195 }
196
197 PyInterp_base::~PyInterp_base()
198 {
199   MESSAGE("PyInterp_base::~PyInterp_base()");
200   salomeAcquireLock();
201   PyThreadState_Swap(_tstate);
202   Py_EndInterpreter(_tstate);
203   salomeReleaseLock();
204 }
205
206 /*!
207  * Must be called by herited classes constructors. initialize() calls virtuals methods
208  * initstate & initcontext, not defined here in base class. initstate & initcontext methods
209  * must be implemented in herited classes, following the Python interpreter policy
210  * (mono or multi interpreter...).
211  */
212 void PyInterp_base::initialize()
213 {
214   MESSAGE("PyInterp_base::initialize()");
215   PyObject *m,*v,*c;
216
217   _history.clear();       // start a new list of user's commands 
218   _ith = _history.begin();
219
220   init_python();
221
222   initState();
223
224   initContext();
225
226   m=PyImport_ImportModule("codeop"); // used to interpret & compile commands
227   if(m == NULL)
228     {
229       MESSAGE("Problem...");
230       PyErr_Print();
231       ASSERT(0);
232       salomeReleaseLock(); 
233       return;
234     }   
235   Py_DECREF(m);   
236   
237   /*
238    *  Create cStringIO to capture stdout and stderr
239    */
240   //PycString_IMPORT;
241   PycStringIO=(PycStringIO_CAPI *)xxxPyCObject_Import("cStringIO", "cStringIO_CAPI");
242   _vout=PycStringIO->NewOutput(128);
243   _verr=PycStringIO->NewOutput(128);
244   
245   // All the initRun outputs are redirected to the standard output (console)
246   this->initRun();
247
248   // We go out of Python world to enter the C++ world. Release the Python global lock 
249   salomeReleaseLock();
250   SCRUTE(_tstate);
251   SCRUTE(this);
252 }
253
254 string PyInterp_base::getbanner()
255 {
256   MESSAGE("PyInterp_base::getbanner()");
257   string banner = "Python ";
258   banner = banner + Py_GetVersion() + " on " + Py_GetPlatform() ;
259   banner = banner + "\ntype help to get general information on environment\n";
260   return banner.c_str();
261 }
262
263 int PyInterp_base::initRun()
264 {
265   MESSAGE("PyInterp_base::initRun()");
266   PySys_SetObject("stderr",_verr);
267   PySys_SetObject("stdout",_vout);
268
269   PyObject *v = PyObject_CallMethod(_verr,"reset","");
270   Py_XDECREF(v);
271   v = PyObject_CallMethod(_vout,"reset","");
272   Py_XDECREF(v);
273
274
275   PyObject *m;
276   m = PyImport_GetModuleDict();
277   
278   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
279   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
280
281   MESSAGE(this->getvout());
282   MESSAGE(this->getverr());
283     
284   return 0;
285 }
286
287 void PyInterp_base::enter()
288 {
289   MESSAGE("PyInterp_base::enter()");
290   salomeAcquireLock();
291   PyThreadState_Swap(_tstate);
292 }
293
294 void PyInterp_base::quit()
295 {
296   MESSAGE("PyInterp_base::quit()");
297   salomeReleaseLock();
298 }
299
300 void PyInterp_base::basicRun(const char *command)
301 {
302   SCRUTE(command);
303   PyObject *code,*r;
304   enter();
305   code=Py_CompileString((char *)command,"PyInterp_base",Py_file_input);
306   if (code == NULL)
307     {
308       /*
309        * Caught an error : SyntaxError
310        * Print it and quit
311        */
312       PyErr_Print();
313       quit();
314       return;
315     }
316   r = PyEval_EvalCode(code,_g,_g);
317   Py_DECREF(code);
318   if (r==NULL)
319     {
320       /*
321        * Caught an error during execution
322        * Print it and quit
323        */
324       PyErr_Print();
325       quit();
326       return;
327     }
328   Py_DECREF(r);
329   quit();
330 }
331
332 int PyInterp_base::run(const char *command)
333 {
334   SCRUTE(command);
335   int ret = 0;
336   if (_atFirst)
337     {
338       _atFirst = false;
339       ret = this->simpleRun("from Help import *");
340       MESSAGE(this->getvout())
341         MESSAGE(this->getverr())
342         if (ret != 0) return ret;
343       ret = this->simpleRun("import salome");
344       MESSAGE(this->getvout());
345       MESSAGE(this->getverr())
346         if (ret != 0) return ret;
347     }
348   ret = this->simpleRun(command);
349   return ret;
350 }
351
352 int PyInterp_base::simpleRun(const char *command)
353 {
354   SCRUTE(command);
355   PyObject *v,*m,*r,*g;
356   char *output;
357   int ier=0;
358   string s_com = command;
359
360   if (s_com.size() > 0)
361     {
362       _history.push_back(s_com);
363       _ith = _history.end();
364       SCRUTE(_history.back());
365     }
366
367   //   SCRUTE(this);
368   //   SCRUTE(_tstate);
369   // We come from C++ to enter Python world
370   // We need to acquire the Python global lock
371   salomeAcquireLock();
372   // Restore the sub interpreter thread state : this._tstate
373   PyThreadState_Swap(_tstate);
374
375   /*
376     Reset redirected outputs before treatment
377   */
378   PySys_SetObject("stderr",_verr);
379   PySys_SetObject("stdout",_vout);
380
381   v = PyObject_CallMethod(_verr,"reset","");
382   Py_XDECREF(v);
383   v = PyObject_CallMethod(_vout,"reset","");
384   Py_XDECREF(v);
385   
386   ier=compile_command(command,_g);
387
388   // Outputs are redirected on standards outputs (console)
389   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
390   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
391
392   // We go back to the C++ world. Release the lock.
393   salomeReleaseLock();
394   return ier;
395 }
396
397 static string vout_buffer;
398 static string verr_buffer;
399
400 char * PyInterp_base::getverr()
401
402   MESSAGE("PyInterp_base::getverr"); 
403   PyObject *v;
404   v=PycStringIO->cgetvalue(_verr);
405   verr_buffer=PyString_AsString(v);
406   Py_DECREF(v);
407   return (char *)verr_buffer.c_str();
408 }
409
410 char * PyInterp_base::getvout()
411 {  
412   MESSAGE("PyInterp_base::getvout"); 
413   PyObject *v;
414   v=PycStringIO->cgetvalue(_vout);
415   vout_buffer=PyString_AsString(v);
416   Py_DECREF(v);
417   return (char *)vout_buffer.c_str();
418 }
419  
420 const char * PyInterp_base::getPrevious()
421 {
422   MESSAGE("PyInterp_base::getPrevious"); 
423   if (_ith != _history.begin())
424     {
425       _ith--;
426       return (*_ith).c_str();
427     }
428   else
429     return BEGIN_HISTORY_PY;
430 }
431
432 const char * PyInterp_base::getNext()
433 {
434   MESSAGE("PyInterp_base::getNext"); 
435   if (_ith != _history.end())
436     {
437       _ith++;
438     }
439   if (_ith == _history.end())
440     return TOP_HISTORY_PY;
441   else
442     return (*_ith).c_str();
443 }