Salome HOME
For qt 5.15 & python 3.8.
[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 #if PY_VERSION_HEX >= 0x03080000
148   0,                            /*tp_vectorcall*/
149 #if PY_VERSION_HEX < 0x03090000
150   0,                            /*tp_print*/
151 #endif
152 #endif
153 };
154
155 #define PyStdOut_Check(v)  ((v)->ob_type == &PyStdOut_Type)
156
157 static PyStdOut* newPyStdOut( bool iscerr )
158 {
159   PyStdOut *self;
160   self = PyObject_New(PyStdOut, &PyStdOut_Type);
161   if (self == NULL)
162     return NULL;
163   self->softspace = 0;
164   self->_cb = NULL;
165   self->_iscerr = iscerr;
166   return self;
167 }
168
169 /*!
170   \class PyInterp_Interp
171   \brief Generic embedded Python interpreter.
172 */
173
174 int   PyInterp_Interp::_argc   = 1;
175 char* PyInterp_Interp::_argv[] = {(char*)""};
176
177 /*!
178   \brief Basic constructor.
179
180   After construction the interpreter instance successor classes
181   must call virtual method initalize().
182 */
183 PyInterp_Interp::PyInterp_Interp():
184   _vout(0), _verr(0), _global_context(0), _local_context(0), _initialized(false)
185 {
186 }
187
188 /*!
189   \brief Destructor.
190 */
191 PyInterp_Interp::~PyInterp_Interp()
192 {
193   destroy();
194 }
195
196 /*!
197   \brief Initialize embedded interpreter.
198
199   This method shoud be called after construction of the interpreter.
200   The method initialize() calls virtuals methods
201   - initPython()  to initialize global Python interpreter
202   - initContext() to initialize interpreter internal context
203   - initRun()     to prepare interpreter for running commands
204   which should be implemented in the successor classes, according to the
205   embedded Python interpreter policy (mono or multi interpreter, etc).
206 */
207 void PyInterp_Interp::initialize()
208 {
209   if ( initialized() )
210     return; // prevent repeating intitialization
211
212   _initialized = true;
213
214   _history.clear();       // start a new list of user's commands
215   _ith = _history.begin();
216
217   initPython();  // This also inits the multi-threading for Python (but w/o acquiring GIL)
218
219   // ---- The rest of the initialisation process is done hodling the GIL
220   PyLockWrapper lck;
221
222   initContext();
223
224   // used to interpret & compile commands - this is really imported here
225   // and only added again (with PyImport_AddModule) later on
226   PyObjWrapper m(PyImport_ImportModule("codeop"));
227   if(!m) {
228     PyErr_Print();
229     return;
230   }
231
232   // Create python objects to capture stdout and stderr
233   _vout=(PyObject*)newPyStdOut( false ); // stdout
234   _verr=(PyObject*)newPyStdOut( true );  // stderr
235
236   // All the initRun outputs are redirected to the standard output (console)
237   initRun();
238 }
239
240 void PyInterp_Interp::destroy()
241 {
242   PyLockWrapper lck;
243   closeContext();
244 }
245
246 /*!
247   \brief Initialize Python interpreter.
248
249   In case if Python is not initialized, it sets program name, initializes the single true Python
250   interpreter, sets program arguments, and initializes threads.
251   Otherwise, does nothing. This is important for light SALOME configuration,
252   as in full SALOME this is done at SalomeApp level.
253   \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server
254  */
255 void PyInterp_Interp::initPython()
256 {
257   if (!Py_IsInitialized()){
258     // Python is not initialized
259     wchar_t **changed_argv = new wchar_t*[_argc]; // Setting arguments
260     for (int i = 0; i < _argc; i++)
261     {
262       changed_argv[i] = Py_DecodeLocale(_argv[i], NULL);
263     }
264    
265     Py_SetProgramName(changed_argv[0]);
266     Py_Initialize(); // Initialize the interpreter
267     PySys_SetArgv(_argc, changed_argv);
268
269     PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
270     PyEval_SaveThread(); // release safely GIL
271   }
272 }
273
274 /*!
275   \brief Get embedded Python interpreter banner.
276   \return banner string
277  */
278 std::string PyInterp_Interp::getBanner() const
279 {
280   PyLockWrapper lck;
281   std::string aBanner("Python ");
282   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
283   aBanner = aBanner + "\ntype help to get general information on environment\n";
284   return aBanner;
285 }
286
287 /*!
288   \brief Initialize run command.
289
290   This method is used to prepare interpreter for running
291   Python commands.
292
293   \return \c true on success and \c false on error
294 */
295 bool PyInterp_Interp::initRun()
296 {
297   return true;
298 }
299
300 /*!
301  * Initialize context dictionaries. GIL is held already.
302  * The code executed in an embedded interpreter is expected to be run at the module
303  * level, in which case local and global context have to be the same dictionary.
304  * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context
305  * for an explanation.
306  */
307 bool PyInterp_Interp::initContext()
308 {
309   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
310   if(!m){
311     PyErr_Print();
312     return false;
313   }
314   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
315   Py_INCREF(_global_context);
316   _local_context = _global_context;
317
318   return true;
319 }
320
321 /*!
322  * Destroy context dictionaries. GIL is held already.
323  */
324 void PyInterp_Interp::closeContext()
325 {
326   Py_XDECREF(_global_context);
327   // both _global_context and _local_context may point to the same Python object
328   if ( _global_context != _local_context)
329     Py_XDECREF(_local_context);
330 }
331
332 /*!
333   \brief Compile Python command and evaluate it in the
334          python dictionary contexts if possible. This is not thread-safe.
335          This is the caller's responsability to make this thread-safe.
336   \internal
337   \param command Python command string
338   \return -1 on fatal error, 1 if command is incomplete and 0
339          if command is executed successfully
340  */
341 static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
342 {
343   PyObject *m = PyImport_AddModule("codeop");
344   if(!m) {
345     // Fatal error. No way to go on.
346     PyErr_Print();
347     return -1;
348   }
349
350   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
351   if(!v) {
352     // Error encountered. It should be SyntaxError,
353     //so we don't write out traceback
354     PyObjWrapper exception, value, tb;
355     PyErr_Fetch(&exception, &value, &tb);
356     PyErr_NormalizeException(&exception, &value, &tb);
357     PyErr_Display(exception, value, NULL);
358     return -1;
359   }
360   else if (v == Py_None) {
361     // Incomplete text we return 1 : we need a complete text to execute
362     return 1;
363   }
364   else {
365     PyObjWrapper r(PyEval_EvalCode((PyObject *)(void *)v,global_ctxt, local_ctxt));
366     if(!r) {
367       // Execution error. We return -1
368       PyErr_Print();
369       return -1;
370     }
371     // The command has been successfully executed. Return 0
372     return 0;
373   }
374 }
375
376 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
377     if(from.empty())
378         return;
379     size_t start_pos = 0;
380     while((start_pos = str.find(from, start_pos)) != std::string::npos) {
381         str.replace(start_pos, from.length(), to);
382         start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
383     }
384 }
385
386 std::vector<std::string>
387 __split(const std::string& str, char delimiter)
388 {
389   std::vector<std::string> internal;
390   std::stringstream ss(str); // Turn the string into a stream.
391   std::string tok;
392
393   while (getline(ss, tok, delimiter)) {
394     internal.push_back(tok);
395   }
396
397   return internal;
398 }
399
400 std::string
401 __join(const std::vector<std::string>& v, int begin=0, int end=-1)
402 {
403   if (end == -1)
404     end = v.size();
405   std::stringstream ss;
406   for (int i = begin; i < end; ++i) {
407     if (i != begin)
408       ss << ",";
409     ss << v[i];
410   }
411   return ss.str();
412 }
413
414 std::vector<std::string>
415 __getArgsList(std::string argsString)
416 {
417   // Special process if some items of 'args:' list are themselves lists
418   // Note that an item can be a list, but not a list of lists...
419   // So we can have something like this:
420   // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
421   // 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'
422   // We have to split argsString to obtain a 9 string elements list
423   std::vector<std::string> x = __split(argsString, ',');
424   bool containsList = (argsString.find('[') != std::string::npos);
425   if (containsList) {
426     std::vector<int> listBeginIndices, listEndIndices;
427     for (int pos = 0; pos < (int)x.size(); ++pos) {
428       if (x[pos][0] == '[')
429         listBeginIndices.push_back(pos);
430       else if (x[pos][x[pos].size()-1] == ']')
431         listEndIndices.push_back(pos);
432     }
433     std::vector<std::string> extractedArgs;
434     int start = 0;
435     for (int pos = 0; pos < (int)listBeginIndices.size(); ++pos) {
436       int lbeg = listBeginIndices[pos];
437       int lend = listEndIndices[pos];
438       if (lbeg > start)
439         for (int k = start; k < lbeg; ++k)
440           extractedArgs.push_back(x[k]);
441       extractedArgs.push_back(__join(x, lbeg, lend+1));
442       start = lend+1;
443     }
444     if (start < (int)x.size())
445       for (int k = start; k < (int)x.size(); ++k)
446         extractedArgs.push_back(x[k]);
447     return extractedArgs;
448   }
449   else {
450     return x;
451   }
452 }
453
454 /*!
455   \brief Compile Python command and evaluate it in the
456          python dictionary context if possible. Command might correspond to
457          the execution of a script with optional arguments.
458          In this case, command is:
459            exec(open(r"/absolute/path/to/script.py", "rb").read(), args=(arg1,...,argn))
460          and args parameter is optional one. This parameter is specified as a tuple of strings.
461   \internal
462   \param command Python command string
463   \param context Python context (dictionary)
464   \return -1 on fatal error, 1 if command is incomplete and 0
465          if command is executed successfully
466  */
467 static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
468 {
469   // First guess if command is execution of a script with args, or a simple Python command
470   QString singleCommand = command;
471   QString commandArgs = "";
472
473   QRegExp rx("exec\\s*\\(.*open\\s*\\(\\s*(.*)\\s*\\)\\s*\\.\\s*read\\s*\\(\\)(\\s*,\\s*args\\s*=\\s*\\(.*\\))\\s*\\)");
474   if (rx.indexIn(command) != -1) {
475     commandArgs = rx.cap(2).remove(0, rx.cap(2).indexOf("(")); // arguments of command
476     commandArgs.insert(commandArgs.indexOf('(')+1, rx.cap(1).split(",")[0].trimmed() + ","); // prepend arguments list by the script file itself
477     singleCommand = singleCommand.remove(rx.pos(2), rx.cap(2).size()); // command for execution without arguments
478   }
479
480   if (commandArgs.isEmpty()) {
481     return run_command(singleCommand.toStdString().c_str(), global_ctxt, local_ctxt);
482   }
483   else {
484     ///////////////std::vector<std::string> argList = __getArgsList(commandArgs);
485     QString preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=list(";
486     QString preCommandEnd = ");";
487     QString postCommand = ";sys.argv=save_argv";
488     QString completeCommand = preCommandBegin+commandArgs+preCommandEnd+singleCommand.trimmed()+postCommand;
489     return run_command(completeCommand.toStdString().c_str(), global_ctxt, local_ctxt);
490   }
491 }
492
493 /*!
494   \brief Run Python command - the command has to fit on a single line (no \n!).
495   Use ';' if you need multiple statements evaluated at once.
496   \param command Python command
497   \return command status
498 */
499 int PyInterp_Interp::run(const char *command)
500 {
501   beforeRun();
502   int ret = simpleRun(command);
503   afterRun();
504   return ret;
505 }
506
507 /**
508  * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
509  * to acquire GIL if needed.
510  */
511 int PyInterp_Interp::beforeRun()
512 {
513   return 0;
514 }
515
516 /**
517  * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability
518  * to acquire GIL if needed.
519  */
520 int PyInterp_Interp::afterRun()
521 {
522   return 0;
523 }
524
525 /*!
526   \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
527   \param command Python command
528   \param addToHistory if \c true (default), the command is added to the commands history
529   \return command status
530 */
531 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
532 {
533   if( addToHistory && strcmp(command,"") != 0 ) {
534     _history.push_back(command);
535     _ith = _history.end();
536   }
537
538   // Current stdout and stderr are saved
539   PyObject * oldOut = PySys_GetObject((char*)"stdout");
540   PyObject * oldErr = PySys_GetObject((char*)"stderr");
541   // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
542   Py_INCREF(oldOut);
543   Py_INCREF(oldErr);
544
545   // Redirect outputs to SALOME Python console before treatment
546   PySys_SetObject((char*)"stderr",_verr);
547   PySys_SetObject((char*)"stdout",_vout);
548
549   int ier = compile_command(command, _global_context, _local_context);
550
551   // Outputs are redirected to what they were before
552   PySys_SetObject((char*)"stdout",oldOut);
553   PySys_SetObject((char*)"stderr",oldErr);
554
555   return ier;
556 }
557
558 /*!
559   \brief Get previous command in the commands history.
560   \return previous command
561 */
562 const char * PyInterp_Interp::getPrevious()
563 {
564   if(_ith != _history.begin()){
565     _ith--;
566     return (*_ith).c_str();
567   }
568   else
569     return BEGIN_HISTORY_PY;
570 }
571
572 /*!
573   \brief Get next command in the commands history.
574   \return next command
575 */
576 const char * PyInterp_Interp::getNext()
577 {
578   if(_ith != _history.end()){
579     _ith++;
580   }
581   if (_ith == _history.end())
582     return TOP_HISTORY_PY;
583   else
584     return (*_ith).c_str();
585 }
586
587 /*!
588   \brief Set Python standard output device hook.
589   \param cb callback function
590   \param data callback function parameters
591 */
592 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
593 {
594   ((PyStdOut*)_vout)->_cb=cb;
595   ((PyStdOut*)_vout)->_data=data;
596 }
597
598 /*!
599   \brief Set Python standard error device hook.
600   \param cb callback function
601   \param data callback function parameters
602 */
603 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
604 {
605   ((PyStdOut*)_verr)->_cb=cb;
606   ((PyStdOut*)_verr)->_data=data;
607 }
608
609 /*!
610   \bried Check if the interpreter is initialized
611   \internal
612 */
613 bool PyInterp_Interp::initialized() const
614 {
615   return _initialized;
616 }