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