Salome HOME
From Community Forum: add isatty() method to embedded interpreter (needed for some...
[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 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 initalize().
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 shoud 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     PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
277     PyEval_SaveThread(); // release safely GIL
278   }
279 }
280
281 /*!
282   \brief Get embedded Python interpreter banner.
283   \return banner string
284  */
285 std::string PyInterp_Interp::getBanner() const
286 {
287   PyLockWrapper lck;
288   std::string aBanner("Python ");
289   aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
290   aBanner = aBanner + "\ntype help to get general information on environment\n";
291   return aBanner;
292 }
293
294 /*!
295   \brief Initialize run command.
296
297   This method is used to prepare interpreter for running
298   Python commands.
299
300   \return \c true on success and \c false on error
301 */
302 bool PyInterp_Interp::initRun()
303 {
304   return true;
305 }
306
307 /*!
308  * Initialize context dictionaries. GIL is held already.
309  * The code executed in an embedded interpreter is expected to be run at the module
310  * level, in which case local and global context have to be the same dictionary.
311  * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context
312  * for an explanation.
313  */
314 bool PyInterp_Interp::initContext()
315 {
316   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
317   if(!m){
318     PyErr_Print();
319     return false;
320   }
321   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
322   Py_INCREF(_global_context);
323   _local_context = _global_context;
324
325   return true;
326 }
327
328 /*!
329  * Destroy context dictionaries. GIL is held already.
330  */
331 void PyInterp_Interp::closeContext()
332 {
333   Py_XDECREF(_global_context);
334   // both _global_context and _local_context may point to the same Python object
335   if ( _global_context != _local_context)
336     Py_XDECREF(_local_context);
337 }
338
339 /*!
340   \brief Compile Python command and evaluate it in the
341          python dictionary contexts if possible. This is not thread-safe.
342          This is the caller's responsability to make this thread-safe.
343   \internal
344   \param command Python command string
345   \return -1 on fatal error, 1 if command is incomplete and 0
346          if command is executed successfully
347  */
348 static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
349 {
350   PyObject *m = PyImport_AddModule("codeop");
351   if(!m) {
352     // Fatal error. No way to go on.
353     PyErr_Print();
354     return -1;
355   }
356
357   PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
358   if(!v) {
359     // Error encountered. It should be SyntaxError,
360     //so we don't write out traceback
361     PyObjWrapper exception, value, tb;
362     PyErr_Fetch(&exception, &value, &tb);
363     PyErr_NormalizeException(&exception, &value, &tb);
364     PyErr_Display(exception, value, NULL);
365     return -1;
366   }
367   else if (v == Py_None) {
368     // Incomplete text we return 1 : we need a complete text to execute
369     return 1;
370   }
371   else {
372     PyObjWrapper r(PyEval_EvalCode((PyObject *)(void *)v,global_ctxt, local_ctxt));
373     if(!r) {
374       // Execution error. We return -1
375       PyErr_Print();
376       return -1;
377     }
378     // The command has been successfully executed. Return 0
379     return 0;
380   }
381 }
382
383 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
384     if(from.empty())
385         return;
386     size_t start_pos = 0;
387     while((start_pos = str.find(from, start_pos)) != std::string::npos) {
388         str.replace(start_pos, from.length(), to);
389         start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
390     }
391 }
392
393 std::vector<std::string>
394 __split(const std::string& str, char delimiter)
395 {
396   std::vector<std::string> internal;
397   std::stringstream ss(str); // Turn the string into a stream.
398   std::string tok;
399
400   while (getline(ss, tok, delimiter)) {
401     internal.push_back(tok);
402   }
403
404   return internal;
405 }
406
407 std::string
408 __join(const std::vector<std::string>& v, int begin=0, int end=-1)
409 {
410   if (end == -1)
411     end = (int)v.size(); //!< TODO: conversion from size_t to int
412   std::stringstream ss;
413   for (int i = begin; i < end; ++i) {
414     if (i != begin)
415       ss << ",";
416     ss << v[i];
417   }
418   return ss.str();
419 }
420
421 std::vector<std::string>
422 __getArgsList(std::string argsString)
423 {
424   // Special process if some items of 'args:' list are themselves lists
425   // Note that an item can be a list, but not a list of lists...
426   // So we can have something like this:
427   // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
428   // 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'
429   // We have to split argsString to obtain a 9 string elements list
430   std::vector<std::string> x = __split(argsString, ',');
431   bool containsList = (argsString.find('[') != std::string::npos);
432   if (containsList) {
433     std::vector<int> listBeginIndices, listEndIndices;
434     for (int pos = 0; pos < (int)x.size(); ++pos) {
435       if (x[pos][0] == '[')
436         listBeginIndices.push_back(pos);
437       else if (x[pos][x[pos].size()-1] == ']')
438         listEndIndices.push_back(pos);
439     }
440     std::vector<std::string> extractedArgs;
441     int start = 0;
442     for (int pos = 0; pos < (int)listBeginIndices.size(); ++pos) {
443       int lbeg = listBeginIndices[pos];
444       int lend = listEndIndices[pos];
445       if (lbeg > start)
446         for (int k = start; k < lbeg; ++k)
447           extractedArgs.push_back(x[k]);
448       extractedArgs.push_back(__join(x, lbeg, lend+1));
449       start = lend+1;
450     }
451     if (start < (int)x.size())
452       for (int k = start; k < (int)x.size(); ++k)
453         extractedArgs.push_back(x[k]);
454     return extractedArgs;
455   }
456   else {
457     return x;
458   }
459 }
460
461 /*!
462   \brief Compile Python command and evaluate it in the
463          python dictionary context if possible. Command might correspond to
464          the execution of a script with optional arguments.
465          In this case, command is:
466            exec(open(r"/absolute/path/to/script.py", "rb").read(), args=(arg1,...,argn))
467          and args parameter is optional one. This parameter is specified as a tuple of strings.
468   \internal
469   \param command Python command string
470   \param context Python context (dictionary)
471   \return -1 on fatal error, 1 if command is incomplete and 0
472          if command is executed successfully
473  */
474 static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
475 {
476   // First guess if command is execution of a script with args, or a simple Python command
477   QString singleCommand = command;
478   QString commandArgs = "";
479
480   QRegExp rx("exec\\s*\\(.*open\\s*\\(\\s*(.*)\\s*\\)\\s*\\.\\s*read\\s*\\(\\)(\\s*,\\s*args\\s*=\\s*\\(.*\\))\\s*\\)");
481   if (rx.indexIn(command) != -1) {
482     commandArgs = rx.cap(2).remove(0, rx.cap(2).indexOf("(")); // arguments of command
483     commandArgs.insert(commandArgs.indexOf('(')+1, rx.cap(1).split(",")[0].trimmed() + ","); // prepend arguments list by the script file itself
484     singleCommand = singleCommand.remove(rx.pos(2), rx.cap(2).size()); // command for execution without arguments
485   }
486
487   if (commandArgs.isEmpty()) {
488     return run_command(singleCommand.toStdString().c_str(), global_ctxt, local_ctxt);
489   }
490   else {
491     ///////////////std::vector<std::string> argList = __getArgsList(commandArgs);
492     QString preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=list(";
493     QString preCommandEnd = ");";
494     QString postCommand = ";sys.argv=save_argv";
495     QString completeCommand = preCommandBegin+commandArgs+preCommandEnd+singleCommand.trimmed()+postCommand;
496     return run_command(completeCommand.toStdString().c_str(), global_ctxt, local_ctxt);
497   }
498 }
499
500 /*!
501   \brief Run Python command - the command has to fit on a single line (no \n!).
502   Use ';' if you need multiple statements evaluated at once.
503   \param command Python command
504   \return command status
505 */
506 int PyInterp_Interp::run(const char *command)
507 {
508   beforeRun();
509   int ret = simpleRun(command);
510   afterRun();
511   return ret;
512 }
513
514 /**
515  * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability
516  * to acquire GIL if needed.
517  */
518 int PyInterp_Interp::beforeRun()
519 {
520   return 0;
521 }
522
523 /**
524  * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability
525  * to acquire GIL if needed.
526  */
527 int PyInterp_Interp::afterRun()
528 {
529   return 0;
530 }
531
532 /*!
533   \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability.
534   \param command Python command
535   \param addToHistory if \c true (default), the command is added to the commands history
536   \return command status
537 */
538 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
539 {
540   if( addToHistory && strcmp(command,"") != 0 ) {
541     _history.push_back(command);
542     _ith = _history.end();
543   }
544
545   // Current stdout and stderr are saved
546   PyObject * oldOut = PySys_GetObject((char*)"stdout");
547   PyObject * oldErr = PySys_GetObject((char*)"stderr");
548   // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
549   Py_INCREF(oldOut);
550   Py_INCREF(oldErr);
551
552   // Redirect outputs to SALOME Python console before treatment
553   PySys_SetObject((char*)"stderr",_verr);
554   PySys_SetObject((char*)"stdout",_vout);
555
556   int ier = compile_command(command, _global_context, _local_context);
557
558   // Outputs are redirected to what they were before
559   PySys_SetObject((char*)"stdout",oldOut);
560   PySys_SetObject((char*)"stderr",oldErr);
561
562   return ier;
563 }
564
565 /*!
566   \brief Get previous command in the commands history.
567   \return previous command
568 */
569 const char * PyInterp_Interp::getPrevious()
570 {
571   if(_ith != _history.begin()){
572     _ith--;
573     return (*_ith).c_str();
574   }
575   else
576     return BEGIN_HISTORY_PY;
577 }
578
579 /*!
580   \brief Get next command in the commands history.
581   \return next command
582 */
583 const char * PyInterp_Interp::getNext()
584 {
585   if(_ith != _history.end()){
586     _ith++;
587   }
588   if (_ith == _history.end())
589     return TOP_HISTORY_PY;
590   else
591     return (*_ith).c_str();
592 }
593
594 /*!
595   \brief Set Python standard output device hook.
596   \param cb callback function
597   \param data callback function parameters
598 */
599 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
600 {
601   ((PyStdOut*)_vout)->_cb=cb;
602   ((PyStdOut*)_vout)->_data=data;
603 }
604
605 /*!
606   \brief Set Python standard error device hook.
607   \param cb callback function
608   \param data callback function parameters
609 */
610 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
611 {
612   ((PyStdOut*)_verr)->_cb=cb;
613   ((PyStdOut*)_verr)->_data=data;
614 }
615
616 /*!
617   \bried Check if the interpreter is initialized
618   \internal
619 */
620 bool PyInterp_Interp::initialized() const
621 {
622   return _initialized;
623 }