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