Salome HOME
Copyright update 2020
[modules/gui.git] / tools / PyInterp / src / PyInterp_Interp.cxx
1 // Copyright (C) 2007-2020  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 //  File   : PyInterp_Interp.cxx
23 //  Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
24
25 #include "PyInterp_Interp.h"  // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
26 #include "PyInterp_Utils.h"
27
28 #include <pythread.h>
29 //#include <cStringIO.h>
30 #include <structmember.h>
31 #include <string>
32 #include <vector>
33 #include <map>
34 #include <iostream>
35 #include <sstream>
36 #include <algorithm>
37
38 #include <QRegExp>
39 #include <QStringList>
40
41 #define TOP_HISTORY_PY   "--- top of history ---"
42 #define BEGIN_HISTORY_PY "--- begin of history ---"
43
44 /*
45   The following functions are used to hook the Python
46   interpreter output.
47 */
48
49 static void
50 PyStdOut_dealloc(PyStdOut *self)
51 {
52   PyObject_Del(self);
53 }
54
55 static PyObject*
56 PyStdOut_write(PyStdOut *self, PyObject *args)
57 {
58   char *c;
59   if (!PyArg_ParseTuple(args, "s",&c))
60     return NULL;
61   if(self->_cb==NULL) {
62     if ( self->_iscerr )
63       std::cerr << c ;
64     else
65       std::cout << c ;
66   }
67   else {
68     self->_cb(self->_data,c);
69   }
70   Py_INCREF(Py_None);
71   return Py_None;
72 }
73
74 static PyObject*
75 PyStdOut_flush(PyStdOut * /*self*/, PyObject * /*args*/)
76 {
77   Py_INCREF(Py_None);
78   return Py_None;
79 }
80
81 static PyMethodDef PyStdOut_methods[] = {
82   {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS, PyDoc_STR("write(string) -> None")},
83   {"flush",  (PyCFunction)PyStdOut_flush,  METH_NOARGS,  PyDoc_STR("flush() -> None")},
84   {NULL, (PyCFunction)NULL, 0, NULL}   /* sentinel */
85 };
86
87 static PyMemberDef PyStdOut_memberlist[] = {
88   {(char*)"softspace", T_INT,  offsetof(PyStdOut, softspace), 0,
89    (char*)"flag indicating that a space needs to be printed; used by print"},
90   {NULL, 0, 0, 0, NULL} /* Sentinel */
91 };
92
93 static PyTypeObject PyStdOut_Type = {
94   /* The ob_type field must be initialized in the module init function
95    * to be portable to Windows without using C++. */
96   PyVarObject_HEAD_INIT(NULL, 0)
97   /*0,*/                            /*ob_size*/
98   "PyOut",                      /*tp_name*/
99   sizeof(PyStdOut),             /*tp_basicsize*/
100   0,                            /*tp_itemsize*/
101   /* methods */
102   (destructor)PyStdOut_dealloc, /*tp_dealloc*/
103   0,                            /*tp_print*/
104   0,                            /*tp_getattr*/
105   0,                            /*tp_setattr*/
106   0,                            /*tp_compare*/
107   0,                            /*tp_repr*/
108   0,                            /*tp_as_number*/
109   0,                            /*tp_as_sequence*/
110   0,                            /*tp_as_mapping*/
111   0,                            /*tp_hash*/
112   0,                            /*tp_call*/
113   0,                            /*tp_str*/
114   PyObject_GenericGetAttr,      /*tp_getattro*/
115   /* softspace is writable:  we must supply tp_setattro */
116   PyObject_GenericSetAttr,      /* tp_setattro */
117   0,                            /*tp_as_buffer*/
118   Py_TPFLAGS_DEFAULT,           /*tp_flags*/
119   0,                            /*tp_doc*/
120   0,                            /*tp_traverse*/
121   0,                            /*tp_clear*/
122   0,                            /*tp_richcompare*/
123   0,                            /*tp_weaklistoffset*/
124   0,                            /*tp_iter*/
125   0,                            /*tp_iternext*/
126   PyStdOut_methods,             /*tp_methods*/
127   PyStdOut_memberlist,          /*tp_members*/
128   0,                            /*tp_getset*/
129   0,                            /*tp_base*/
130   0,                            /*tp_dict*/
131   0,                            /*tp_descr_get*/
132   0,                            /*tp_descr_set*/
133   0,                            /*tp_dictoffset*/
134   0,                            /*tp_init*/
135   0,                            /*tp_alloc*/
136   0,                            /*tp_new*/
137   0,                            /*tp_free*/
138   0,                            /*tp_is_gc*/
139   0,                            /*tp_bases*/
140   0,                            /*tp_mro*/
141   0,                            /*tp_cache*/
142   0,                            /*tp_subclasses*/
143   0,                            /*tp_weaklist*/
144   0,                            /*tp_del*/
145   0,                            /*tp_version_tag*/
146   0,                            /*tp_finalize*/
147 };
148
149 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
150
151 static PyStdOut* newPyStdOut( bool iscerr )
152 {
153   PyStdOut *self;
154   self = PyObject_New(PyStdOut, &PyStdOut_Type);
155   if (self == NULL)
156     return NULL;
157   self->softspace = 0;
158   self->_cb = NULL;
159   self->_iscerr = iscerr;
160   return self;
161 }
162
163 /*!
164   \class PyInterp_Interp
165   \brief Generic embedded Python interpreter.
166 */
167
168 int   PyInterp_Interp::_argc   = 1;
169 char* PyInterp_Interp::_argv[] = {(char*)""};
170
171 /*!
172   \brief Basic constructor.
173
174   After construction the interpreter instance successor classes
175   must call virtual method initalize().
176 */
177 PyInterp_Interp::PyInterp_Interp():
178   _vout(0), _verr(0), _global_context(0), _local_context(0), _initialized(false)
179 {
180 }
181
182 /*!
183   \brief Destructor.
184 */
185 PyInterp_Interp::~PyInterp_Interp()
186 {
187   destroy();
188 }
189
190 /*!
191   \brief Initialize embedded interpreter.
192
193   This method shoud be called after construction of the interpreter.
194   The method initialize() calls virtuals methods
195   - initPython()  to initialize global Python interpreter
196   - initContext() to initialize interpreter internal context
197   - initRun()     to prepare interpreter for running commands
198   which should be implemented in the successor classes, according to the
199   embedded Python interpreter policy (mono or multi interpreter, etc).
200 */
201 void PyInterp_Interp::initialize()
202 {
203   if ( initialized() )
204     return; // prevent repeating intitialization
205
206   _initialized = true;
207
208   _history.clear();       // start a new list of user's commands
209   _ith = _history.begin();
210
211   initPython();  // This also inits the multi-threading for Python (but w/o acquiring GIL)
212
213   // ---- The rest of the initialisation process is done hodling the GIL
214   PyLockWrapper lck;
215
216   initContext();
217
218   // used to interpret & compile commands - this is really imported here
219   // and only added again (with PyImport_AddModule) later on
220   PyObjWrapper m(PyImport_ImportModule("codeop"));
221   if(!m) {
222     PyErr_Print();
223     return;
224   }
225
226   // Create python objects to capture stdout and stderr
227   _vout=(PyObject*)newPyStdOut( false ); // stdout
228   _verr=(PyObject*)newPyStdOut( true );  // stderr
229
230   // All the initRun outputs are redirected to the standard output (console)
231   initRun();
232 }
233
234 void PyInterp_Interp::destroy()
235 {
236   PyLockWrapper lck;
237   closeContext();
238 }
239
240 /*!
241   \brief Initialize Python interpreter.
242
243   In case if Python is not initialized, it sets program name, initializes the single true Python
244   interpreter, sets program arguments, and initializes threads.
245   Otherwise, does nothing. This is important for light SALOME configuration,
246   as in full SALOME this is done at SalomeApp level.
247   \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server
248  */
249 void PyInterp_Interp::initPython()
250 {
251   if (!Py_IsInitialized()){
252     // Python is not initialized
253     wchar_t **changed_argv = new wchar_t*[_argc]; // Setting arguments
254     for (int i = 0; i < _argc; i++)
255     {
256       changed_argv[i] = Py_DecodeLocale(_argv[i], NULL);
257     }
258    
259     Py_SetProgramName(changed_argv[0]);
260     Py_Initialize(); // Initialize the interpreter
261     PySys_SetArgv(_argc, changed_argv);
262
263     PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
264     PyEval_SaveThread(); // release safely GIL
265   }
266 }
267
268 /*!
269   \brief Get embedded Python interpreter banner.
270   \return banner string
271  */
272 std::string PyInterp_Interp::getBanner() const
273 {
274   PyLockWrapper lck;
275   std::string aBanner("Python ");
276   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
277   aBanner = aBanner + "\ntype help to get general information on environment\n";
278   return aBanner;
279 }
280
281 /*!
282   \brief Initialize run command.
283
284   This method is used to prepare interpreter for running
285   Python commands.
286
287   \return \c true on success and \c false on error
288 */
289 bool PyInterp_Interp::initRun()
290 {
291   return true;
292 }
293
294 /*!
295  * Initialize context dictionaries. GIL is held already.
296  * The code executed in an embedded interpreter is expected to be run at the module
297  * level, in which case local and global context have to be the same dictionary.
298  * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context
299  * for an explanation.
300  */
301 bool PyInterp_Interp::initContext()
302 {
303   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
304   if(!m){
305     PyErr_Print();
306     return false;
307   }
308   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
309   Py_INCREF(_global_context);
310   _local_context = _global_context;
311
312   return true;
313 }
314
315 /*!
316  * Destroy context dictionaries. GIL is held already.
317  */
318 void PyInterp_Interp::closeContext()
319 {
320   Py_XDECREF(_global_context);
321   // both _global_context and _local_context may point to the same Python object
322   if ( _global_context != _local_context)
323     Py_XDECREF(_local_context);
324 }
325
326 /*!
327   \brief Compile Python command and evaluate it in the
328          python dictionary contexts if possible. This is not thread-safe.
329          This is the caller's responsability to make this thread-safe.
330   \internal
331   \param command Python command string
332   \return -1 on fatal error, 1 if command is incomplete and 0
333          if command is executed successfully
334  */
335 static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
336 {
337   PyObject *m = PyImport_AddModule("codeop");
338   if(!m) {
339     // Fatal error. No way to go on.
340     PyErr_Print();
341     return -1;
342   }
343
344   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
345   if(!v) {
346     // Error encountered. It should be SyntaxError,
347     //so we don't write out traceback
348     PyObjWrapper exception, value, tb;
349     PyErr_Fetch(&exception, &value, &tb);
350     PyErr_NormalizeException(&exception, &value, &tb);
351     PyErr_Display(exception, value, NULL);
352     return -1;
353   }
354   else if (v == Py_None) {
355     // Incomplete text we return 1 : we need a complete text to execute
356     return 1;
357   }
358   else {
359     PyObjWrapper r(PyEval_EvalCode((PyObject *)(void *)v,global_ctxt, local_ctxt));
360     if(!r) {
361       // Execution error. We return -1
362       PyErr_Print();
363       return -1;
364     }
365     // The command has been successfully executed. Return 0
366     return 0;
367   }
368 }
369
370 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
371     if(from.empty())
372         return;
373     size_t start_pos = 0;
374     while((start_pos = str.find(from, start_pos)) != std::string::npos) {
375         str.replace(start_pos, from.length(), to);
376         start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
377     }
378 }
379
380 std::vector<std::string>
381 __split(const std::string& str, char delimiter)
382 {
383   std::vector<std::string> internal;
384   std::stringstream ss(str); // Turn the string into a stream.
385   std::string tok;
386
387   while (getline(ss, tok, delimiter)) {
388     internal.push_back(tok);
389   }
390
391   return internal;
392 }
393
394 std::string
395 __join(const std::vector<std::string>& v, int begin=0, int end=-1)
396 {
397   if (end == -1)
398     end = v.size();
399   std::stringstream ss;
400   for (int i = begin; i < end; ++i) {
401     if (i != begin)
402       ss << ",";
403     ss << v[i];
404   }
405   return ss.str();
406 }
407
408 std::vector<std::string>
409 __getArgsList(std::string argsString)
410 {
411   // Special process if some items of 'args:' list are themselves lists
412   // Note that an item can be a list, but not a list of lists...
413   // So we can have something like this:
414   // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
415   // With such a call, argsString variable contains the string representing ['file1','file2'],'val1','done',[1,2,3],[True,False],'ok',kwarg1='kwarg1',kwarg2='kwarg2','fin'
416   // We have to split argsString to obtain a 9 string elements list
417   std::vector<std::string> x = __split(argsString, ',');
418   bool containsList = (argsString.find('[') != std::string::npos);
419   if (containsList) {
420     std::vector<int> listBeginIndices, listEndIndices;
421     for (int pos = 0; pos < (int)x.size(); ++pos) {
422       if (x[pos][0] == '[')
423         listBeginIndices.push_back(pos);
424       else if (x[pos][x[pos].size()-1] == ']')
425         listEndIndices.push_back(pos);
426     }
427     std::vector<std::string> extractedArgs;
428     int start = 0;
429     for (int pos = 0; pos < (int)listBeginIndices.size(); ++pos) {
430       int lbeg = listBeginIndices[pos];
431       int lend = listEndIndices[pos];
432       if (lbeg > start)
433         for (int k = start; k < lbeg; ++k)
434           extractedArgs.push_back(x[k]);
435       extractedArgs.push_back(__join(x, lbeg, lend+1));
436       start = lend+1;
437     }
438     if (start < (int)x.size())
439       for (int k = start; k < (int)x.size(); ++k)
440         extractedArgs.push_back(x[k]);
441     return extractedArgs;
442   }
443   else {
444     return x;
445   }
446 }
447
448 /*!
449   \brief Compile Python command and evaluate it in the
450          python dictionary context if possible. Command might correspond to
451          the execution of a script with optional arguments.
452          In this case, command is:
453            exec(open(r"/absolute/path/to/script.py", "rb").read(), args=(arg1,...,argn))
454          and args parameter is optional one. This parameter is specified as a tuple of strings.
455   \internal
456   \param command Python command string
457   \param context Python context (dictionary)
458   \return -1 on fatal error, 1 if command is incomplete and 0
459          if command is executed successfully
460  */
461 static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
462 {
463   // First guess if command is execution of a script with args, or a simple Python command
464   QString singleCommand = command;
465   QString commandArgs = "";
466
467   QRegExp rx("exec\\s*\\(.*open\\s*\\(\\s*(.*)\\s*\\)\\s*\\.\\s*read\\s*\\(\\)(\\s*,\\s*args\\s*=\\s*\\(.*\\))\\s*\\)");
468   if (rx.indexIn(command) != -1) {
469     commandArgs = rx.cap(2).remove(0, rx.cap(2).indexOf("(")); // arguments of command
470     commandArgs.insert(commandArgs.indexOf('(')+1, rx.cap(1).split(",")[0].trimmed() + ","); // prepend arguments list by the script file itself
471     singleCommand = singleCommand.remove(rx.pos(2), rx.cap(2).size()); // command for execution without arguments
472   }
473
474   if (commandArgs.isEmpty()) {
475     return run_command(singleCommand.toStdString().c_str(), global_ctxt, local_ctxt);
476   }
477   else {
478     ///////////////std::vector<std::string> argList = __getArgsList(commandArgs);
479     QString preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=list(";
480     QString preCommandEnd = ");";
481     QString postCommand = ";sys.argv=save_argv";
482     QString completeCommand = preCommandBegin+commandArgs+preCommandEnd+singleCommand.trimmed()+postCommand;
483     return run_command(completeCommand.toStdString().c_str(), global_ctxt, local_ctxt);
484   }
485 }
486
487 /*!
488   \brief Run Python command - the command has to fit on a single line (no \n!).
489   Use ';' if you need multiple statements evaluated at once.
490   \param command Python command
491   \return command status
492 */
493 int PyInterp_Interp::run(const char *command)
494 {
495   beforeRun();
496   int ret = simpleRun(command);
497   afterRun();
498   return ret;
499 }
500
501 /**
502  * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
503  * to acquire GIL if needed.
504  */
505 int PyInterp_Interp::beforeRun()
506 {
507   return 0;
508 }
509
510 /**
511  * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability
512  * to acquire GIL if needed.
513  */
514 int PyInterp_Interp::afterRun()
515 {
516   return 0;
517 }
518
519 /*!
520   \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
521   \param command Python command
522   \param addToHistory if \c true (default), the command is added to the commands history
523   \return command status
524 */
525 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
526 {
527   if( addToHistory && strcmp(command,"") != 0 ) {
528     _history.push_back(command);
529     _ith = _history.end();
530   }
531
532   // Current stdout and stderr are saved
533   PyObject * oldOut = PySys_GetObject((char*)"stdout");
534   PyObject * oldErr = PySys_GetObject((char*)"stderr");
535   // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
536   Py_INCREF(oldOut);
537   Py_INCREF(oldErr);
538
539   // Redirect outputs to SALOME Python console before treatment
540   PySys_SetObject((char*)"stderr",_verr);
541   PySys_SetObject((char*)"stdout",_vout);
542
543   int ier = compile_command(command, _global_context, _local_context);
544
545   // Outputs are redirected to what they were before
546   PySys_SetObject((char*)"stdout",oldOut);
547   PySys_SetObject((char*)"stderr",oldErr);
548
549   return ier;
550 }
551
552 /*!
553   \brief Get previous command in the commands history.
554   \return previous command
555 */
556 const char * PyInterp_Interp::getPrevious()
557 {
558   if(_ith != _history.begin()){
559     _ith--;
560     return (*_ith).c_str();
561   }
562   else
563     return BEGIN_HISTORY_PY;
564 }
565
566 /*!
567   \brief Get next command in the commands history.
568   \return next command
569 */
570 const char * PyInterp_Interp::getNext()
571 {
572   if(_ith != _history.end()){
573     _ith++;
574   }
575   if (_ith == _history.end())
576     return TOP_HISTORY_PY;
577   else
578     return (*_ith).c_str();
579 }
580
581 /*!
582   \brief Set Python standard output device hook.
583   \param cb callback function
584   \param data callback function parameters
585 */
586 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
587 {
588   ((PyStdOut*)_vout)->_cb=cb;
589   ((PyStdOut*)_vout)->_data=data;
590 }
591
592 /*!
593   \brief Set Python standard error device hook.
594   \param cb callback function
595   \param data callback function parameters
596 */
597 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
598 {
599   ((PyStdOut*)_verr)->_cb=cb;
600   ((PyStdOut*)_verr)->_data=data;
601 }
602
603 /*!
604   \bried Check if the interpreter is initialized
605   \internal
606 */
607 bool PyInterp_Interp::initialized() const
608 {
609   return _initialized;
610 }