Salome HOME
Fix pb with persistence of "light" modules: SaveAs operation leads to loss of non...
[modules/gui.git] / src / PyInterp / PyInterp_Interp.cxx
1 // Copyright (C) 2007-2014  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, or (at your option) any later version.
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 #include <algorithm>
38
39 #define TOP_HISTORY_PY   "--- top of history ---"
40 #define BEGIN_HISTORY_PY "--- begin of history ---"
41
42 // a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state)
43 std::map<long,PyThreadState*> currentThreadMap;
44
45 /*!
46   \class PyLockWrapper
47   \brief Python GIL wrapper.
48 */
49
50 /*!
51   \brief Constructor. Automatically acquires GIL.
52   \param theThreadState python thread state
53 */
54 PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState):
55   myThreadState(theThreadState),
56   mySaveThreadState(0)
57 {
58   if (myThreadState->interp == PyInterp_Interp::_interp)
59     _savestate = PyGILState_Ensure();
60   else
61     PyEval_AcquireThread(myThreadState);
62 }
63
64 /*!
65   \brief Destructor. Automatically releases GIL.
66 */
67 PyLockWrapper::~PyLockWrapper()
68 {
69   if (myThreadState->interp == PyInterp_Interp::_interp)
70     PyGILState_Release(_savestate);
71   else
72     PyEval_ReleaseThread(myThreadState);
73 }
74
75 /*!
76   \brief Get Python GIL wrapper.
77   \return GIL lock wrapper (GIL is automatically acquired here)
78 */
79 PyLockWrapper PyInterp_Interp::GetLockWrapper()
80 {
81   if (_tstate->interp == PyInterp_Interp::_interp)
82     return _tstate;
83
84   // If we are here, we have a secondary python interpreter. Try to get a thread state synchronized with the system thread
85   long currentThreadid=PyThread_get_thread_ident(); // the system thread id
86   PyThreadState* theThreadState;
87   if(currentThreadMap.count(currentThreadid) != 0)
88     {
89       //a thread state exists for this thread id
90       PyThreadState* oldThreadState=currentThreadMap[currentThreadid];
91       if(_tstate->interp ==oldThreadState->interp)
92         {
93           //The old thread state has the same python interpreter as this one : reuse the threadstate
94           theThreadState=oldThreadState;
95         }
96       else
97         {
98           //The old thread state has not the same python interpreter as this one : delete the old threadstate and create a new one
99           PyEval_AcquireLock();
100           PyThreadState_Clear(oldThreadState);
101           PyThreadState_Delete(oldThreadState);
102           PyEval_ReleaseLock();
103           theThreadState=PyThreadState_New(_tstate->interp);
104           currentThreadMap[currentThreadid]=theThreadState;
105         }
106     }
107   else
108     {
109       // no old thread state for this thread id : create a new one
110       theThreadState=PyThreadState_New(_tstate->interp);
111       currentThreadMap[currentThreadid]=theThreadState;
112     }
113   return theThreadState;
114 }
115
116 /*
117   The following functions are used to hook the Python
118   interpreter output.
119 */
120
121 static void
122 PyStdOut_dealloc(PyStdOut *self)
123 {
124   PyObject_Del(self);
125 }
126
127 static PyObject*
128 PyStdOut_write(PyStdOut *self, PyObject *args)
129 {
130   char *c;
131   int l;
132   if (!PyArg_ParseTuple(args, "t#:write",&c, &l))
133     return NULL;
134   if(self->_cb==NULL) {
135     if ( self->_iscerr )
136       std::cerr << c ;
137     else
138       std::cout << c ;
139   }
140   else {
141     self->_cb(self->_data,c);
142   }
143   Py_INCREF(Py_None);
144   return Py_None;
145 }
146
147 static PyObject*
148 PyStdOut_flush(PyStdOut *self)
149 {
150   Py_INCREF(Py_None);
151   return Py_None;
152 }
153
154 static PyMethodDef PyStdOut_methods[] = {
155   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
156   {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
157   {NULL,    NULL}   /* sentinel */
158 };
159
160 static PyMemberDef PyStdOut_memberlist[] = {
161   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
162    (char*)"flag indicating that a space needs to be printed; used by print"},
163   {NULL} /* Sentinel */
164 };
165
166 static PyTypeObject PyStdOut_Type = {
167   /* The ob_type field must be initialized in the module init function
168    * to be portable to Windows without using C++. */
169   PyObject_HEAD_INIT(NULL)
170   0,                            /*ob_size*/
171   "PyOut",                      /*tp_name*/
172   sizeof(PyStdOut),             /*tp_basicsize*/
173   0,                            /*tp_itemsize*/
174   /* methods */
175   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
176   0,                            /*tp_print*/
177   0,                            /*tp_getattr*/
178   0,                            /*tp_setattr*/
179   0,                            /*tp_compare*/
180   0,                            /*tp_repr*/
181   0,                            /*tp_as_number*/
182   0,                            /*tp_as_sequence*/
183   0,                            /*tp_as_mapping*/
184   0,                            /*tp_hash*/
185   0,                            /*tp_call*/
186   0,                            /*tp_str*/
187   PyObject_GenericGetAttr,      /*tp_getattro*/
188   /* softspace is writable:  we must supply tp_setattro */
189   PyObject_GenericSetAttr,      /* tp_setattro */
190   0,                            /*tp_as_buffer*/
191   Py_TPFLAGS_DEFAULT,           /*tp_flags*/
192   0,                            /*tp_doc*/
193   0,                            /*tp_traverse*/
194   0,                            /*tp_clear*/
195   0,                            /*tp_richcompare*/
196   0,                            /*tp_weaklistoffset*/
197   0,                            /*tp_iter*/
198   0,                            /*tp_iternext*/
199   PyStdOut_methods,             /*tp_methods*/
200   PyStdOut_memberlist,          /*tp_members*/
201   0,                            /*tp_getset*/
202   0,                            /*tp_base*/
203   0,                            /*tp_dict*/
204   0,                            /*tp_descr_get*/
205   0,                            /*tp_descr_set*/
206   0,                            /*tp_dictoffset*/
207   0,                            /*tp_init*/
208   0,                            /*tp_alloc*/
209   0,                            /*tp_new*/
210   0,                            /*tp_free*/
211   0,                            /*tp_is_gc*/
212 };
213
214 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
215
216 static PyStdOut* newPyStdOut( bool iscerr )
217 {
218   PyStdOut *self;
219   self = PyObject_New(PyStdOut, &PyStdOut_Type);
220   if (self == NULL)
221     return NULL;
222   self->softspace = 0;
223   self->_cb = NULL;
224   self->_iscerr = iscerr;
225   return self;
226 }
227
228 /*!
229   \class PyInterp_Interp
230   \brief Generic embedded Python interpreter.
231 */
232
233 int   PyInterp_Interp::_argc   = 1;
234 char* PyInterp_Interp::_argv[] = {(char*)""};
235 PyObject*           PyInterp_Interp::builtinmodule = NULL;
236 PyThreadState*      PyInterp_Interp::_gtstate      = NULL;
237 PyInterpreterState* PyInterp_Interp::_interp       = NULL;
238
239 /*!
240   \brief Basic constructor.
241
242   After construction the interpreter instance successor classes
243   must call virtual method initalize().
244 */
245 PyInterp_Interp::PyInterp_Interp():
246   _tstate(0), _vout(0), _verr(0), _g(0)
247 {
248 }
249
250 /*!
251   \brief Destructor.
252 */
253 PyInterp_Interp::~PyInterp_Interp()
254 {
255 }
256
257 /*!
258   \brief Initialize embedded interpreter.
259
260   This method shoud be called after construction of the interpreter.
261   The method initialize() calls virtuals methods
262   - initPython()  to initialize global Python interpreter
263   - initState()   to initialize embedded interpreter state
264   - initContext() to initialize interpreter internal context
265   - initRun()     to prepare interpreter for running commands
266   which should be implemented in the successor classes, according to the
267   embedded Python interpreter policy (mono or multi interpreter, etc).
268 */
269 void PyInterp_Interp::initialize()
270 {
271   _history.clear();       // start a new list of user's commands
272   _ith = _history.begin();
273
274   initPython();
275   // Here the global lock is released
276
277   initState();
278
279   PyEval_AcquireThread(_tstate);
280
281   initContext();
282
283   // used to interpret & compile commands
284   PyObjWrapper m(PyImport_ImportModule("codeop"));
285   if(!m) {
286     PyErr_Print();
287     PyEval_ReleaseThread(_tstate);
288     return;
289   }
290
291   // Create python objects to capture stdout and stderr
292   _vout=(PyObject*)newPyStdOut( false ); // stdout
293   _verr=(PyObject*)newPyStdOut( true );  // stderr
294
295   // All the initRun outputs are redirected to the standard output (console)
296   initRun();
297   PyEval_ReleaseThread(_tstate);
298 }
299
300 /*!
301   \brief Initialize Python interpreter.
302
303   In case if Python is not initialized, it sets program name, initializes the interpreter, sets program arguments,
304   initializes threads.
305   Otherwise, it just obtains the global interpreter and thread states. This is important for light SALOME configuration,
306   as in full SALOME this is done at SalomeApp level.
307   \sa SalomeApp_PyInterp class
308  */
309 void PyInterp_Interp::initPython()
310 {
311   if (!Py_IsInitialized()){
312     // Python is not initialized
313     Py_SetProgramName(_argv[0]);
314     Py_Initialize(); // Initialize the interpreter
315     PySys_SetArgv(_argc, _argv);
316     PyEval_InitThreads(); // Create (and acquire) the interpreter lock
317   }
318
319   if ( _interp == NULL )
320     _interp = PyThreadState_Get()->interp;
321   if (PyType_Ready(&PyStdOut_Type) < 0) {
322     PyErr_Print();
323   }
324   if ( _gtstate == NULL )
325     _gtstate = PyEval_SaveThread(); // Release global thread state
326 }
327
328 /*!
329   \brief Get embedded Python interpreter banner.
330   \return banner string
331  */
332 std::string PyInterp_Interp::getbanner()
333 {
334  // Should we take the lock ?
335  // PyEval_RestoreThread(_tstate);
336   std::string aBanner("Python ");
337   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
338   aBanner = aBanner + "\ntype help to get general information on environment\n";
339   //PyEval_SaveThread();
340   return aBanner;
341 }
342
343 /*!
344   \brief Initialize run command.
345
346   This method is used to prepare interpreter for running
347   Python commands.
348
349   \return \c true on success and \c false on error
350 */
351 bool PyInterp_Interp::initRun()
352 {
353   //
354   // probably all below code isn't required
355   //
356   /*
357   PySys_SetObject("stderr",_verr);
358   PySys_SetObject("stdout",_vout);
359
360   //PyObject *m = PyImport_GetModuleDict();
361
362   PySys_SetObject("stdout",PySys_GetObject("__stdout__"));
363   PySys_SetObject("stderr",PySys_GetObject("__stderr__"));
364   */
365   return true;
366 }
367
368 /*!
369   \brief Compile Python command and evaluate it in the
370          python dictionary context if possible.
371   \internal
372   \param command Python command string
373   \param context Python context (dictionary)
374   \return -1 on fatal error, 1 if command is incomplete and 0
375          if command is executed successfully
376  */
377 static int run_command(const char *command, PyObject *context)
378 {
379   PyObject *m = PyImport_AddModule("codeop");
380   if(!m) { // Fatal error. No way to go on.
381     PyErr_Print();
382     return -1;
383   }
384   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
385   if(!v) {
386     // Error encountered. It should be SyntaxError,
387     //so we don't write out traceback
388     PyObjWrapper exception, value, tb;
389     PyErr_Fetch(&exception, &value, &tb);
390     PyErr_NormalizeException(&exception, &value, &tb);
391     PyErr_Display(exception, value, NULL);
392     return -1;
393   }
394   else if (v == Py_None) {
395     // Incomplete text we return 1 : we need a complete text to execute
396     return 1;
397   }
398   else {
399     // Complete and correct text. We evaluate it.
400     //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0
401     //    PyObjWrapper r(PyEval_EvalCode(v,context,context));
402     //#else
403     PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context));
404     //#endif
405     if(!r) {
406       // Execution error. We return -1
407       PyErr_Print();
408       return -1;
409     }
410     // The command has been successfully executed. Return 0
411     return 0;
412   }
413 }
414
415 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
416     if(from.empty())
417         return;
418     size_t start_pos = 0;
419     while((start_pos = str.find(from, start_pos)) != std::string::npos) {
420         str.replace(start_pos, from.length(), to);
421         start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
422     }
423 }
424 /*!
425   \brief Compile Python command and evaluate it in the
426          python dictionary context if possible. Command might correspond to
427          the execution of a script with optional arguments.
428          In this case, command is:
429          execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
430   \internal
431   \param command Python command string
432   \param context Python context (dictionary)
433   \return -1 on fatal error, 1 if command is incomplete and 0
434          if command is executed successfully
435  */
436 static int compile_command(const char *command,PyObject *context)
437 {
438   // First guess if command is execution of a script with args, or a simple Python command
439   std::string singleCommand = command;
440   std::string commandArgs = "";
441
442   std::size_t pos = std::string(command).find("args:");
443   if (pos != std::string::npos) {
444     commandArgs = singleCommand.substr(pos+5);
445     commandArgs = commandArgs.substr(0, commandArgs.length()-3);
446     singleCommand = singleCommand.substr(0, pos-1)+"\")";
447   }
448
449   if (commandArgs.empty()) {
450     // process command: expression
451     // process command: execfile(r"/absolute/path/to/script.py") (no args)
452     return run_command(singleCommand.c_str(), context);
453   }
454   else {
455     // process command: execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]")
456     std::string script = singleCommand.substr(11); // remove leading execfile(r"
457     script = script.substr(0, script.length()-2); // remove trailing ")
458
459     std::string preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=[";
460     std::string preCommandEnd = "];";
461     replaceAll(commandArgs, ",", "\",\"");
462     commandArgs = "\""+commandArgs+"\"";
463     std::string completeCommand = preCommandBegin+"\""+script+"\","+commandArgs+preCommandEnd+singleCommand+";sys.argv=save_argv";
464     return run_command(completeCommand.c_str(), context);
465   }
466 }
467
468 /*!
469   \brief Run Python command.
470   \param command Python command
471   \return command status
472 */
473 int PyInterp_Interp::run(const char *command)
474 {
475   beforeRun();
476   return simpleRun(command);
477 }
478
479 /*!
480   \brief Run Python command (used internally).
481   \param command Python command
482   \param addToHistory if \c true (default), the command is added to the commands history
483   \return command status
484 */
485 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
486 {
487   if( addToHistory && strcmp(command,"") != 0 ) {
488     _history.push_back(command);
489     _ith = _history.end();
490   }
491
492   // We come from C++ to enter Python world
493   // We need to acquire the Python global lock
494   //PyLockWrapper aLock(_tstate); // san - lock is centralized now
495
496   // Reset redirected outputs before treatment
497   PySys_SetObject((char*)"stderr",_verr);
498   PySys_SetObject((char*)"stdout",_vout);
499
500   int ier = compile_command(command,_g);
501
502   // Outputs are redirected on standards outputs (console)
503   PySys_SetObject((char*)"stdout",PySys_GetObject((char*)"__stdout__"));
504   PySys_SetObject((char*)"stderr",PySys_GetObject((char*)"__stderr__"));
505
506   return ier;
507 }
508
509 /*!
510   \brief Get previous command in the commands history.
511   \return previous command
512 */
513 const char * PyInterp_Interp::getPrevious()
514 {
515   if(_ith != _history.begin()){
516     _ith--;
517     return (*_ith).c_str();
518   }
519   else
520     return BEGIN_HISTORY_PY;
521 }
522
523 /*!
524   \brief Get next command in the commands history.
525   \return next command
526 */
527 const char * PyInterp_Interp::getNext()
528 {
529   if(_ith != _history.end()){
530     _ith++;
531   }
532   if (_ith == _history.end())
533     return TOP_HISTORY_PY;
534   else
535     return (*_ith).c_str();
536 }
537
538 /*!
539   \brief Set Python standard output device hook.
540   \param cb callback function
541   \param data callback function parameters
542 */
543 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
544 {
545   ((PyStdOut*)_vout)->_cb=cb;
546   ((PyStdOut*)_vout)->_data=data;
547 }
548
549 /*!
550   \brief Set Python standard error device hook.
551   \param cb callback function
552   \param data callback function parameters
553 */
554 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
555 {
556   ((PyStdOut*)_verr)->_cb=cb;
557   ((PyStdOut*)_verr)->_data=data;
558 }