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