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