1 // Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // File : PyInterp_Interp.cxx
23 // Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON
25 #include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!!
26 #include "PyInterp_Utils.h"
29 //#include <cStringIO.h>
30 #include <structmember.h>
38 #include <QRegularExpression>
39 #include <QStringList>
41 #define TOP_HISTORY_PY "--- top of history ---"
42 #define BEGIN_HISTORY_PY "--- begin of history ---"
45 The following functions are used to hook the Python
50 PyStdOut_dealloc(PyStdOut *self)
56 PyStdOut_write(PyStdOut *self, PyObject *args)
59 if (!PyArg_ParseTuple(args, "s",&c))
68 self->_cb(self->_data,c);
75 PyStdOut_flush(PyStdOut * /*self*/, PyObject * /*args*/)
82 PyStdOut_isatty(PyStdOut * /*self*/, PyObject */*args*/)
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 */
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 */
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)
106 sizeof(PyStdOut), /*tp_basicsize*/
109 (destructor)PyStdOut_dealloc, /*tp_dealloc*/
116 0, /*tp_as_sequence*/
121 PyObject_GenericGetAttr, /*tp_getattro*/
122 /* softspace is writable: we must supply tp_setattro */
123 PyObject_GenericSetAttr, /* tp_setattro */
125 Py_TPFLAGS_DEFAULT, /*tp_flags*/
129 0, /*tp_richcompare*/
130 0, /*tp_weaklistoffset*/
133 PyStdOut_methods, /*tp_methods*/
134 PyStdOut_memberlist, /*tp_members*/
152 0, /*tp_version_tag*/
154 #if PY_VERSION_HEX >= 0x03080000
156 #if PY_VERSION_HEX < 0x03090000
162 #define PyStdOut_Check(v) ((v)->ob_type == &PyStdOut_Type)
164 static PyStdOut* newPyStdOut( bool iscerr )
167 self = PyObject_New(PyStdOut, &PyStdOut_Type);
172 self->_iscerr = iscerr;
177 \class PyInterp_Interp
178 \brief Generic embedded Python interpreter.
181 int PyInterp_Interp::_argc = 1;
182 char* PyInterp_Interp::_argv[] = {(char*)""};
185 \brief Basic constructor.
187 After construction the interpreter instance successor classes
188 must call virtual method initialize().
190 PyInterp_Interp::PyInterp_Interp():
191 _vout(0), _verr(0), _global_context(0), _local_context(0), _initialized(false)
198 PyInterp_Interp::~PyInterp_Interp()
204 \brief Initialize embedded interpreter.
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).
214 void PyInterp_Interp::initialize()
217 return; // prevent repeating intitialization
221 _history.clear(); // start a new list of user's commands
222 _ith = _history.begin();
224 initPython(); // This also inits the multi-threading for Python (but w/o acquiring GIL)
226 // ---- The rest of the initialisation process is done hodling the GIL
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"));
239 // Create python objects to capture stdout and stderr
240 _vout=(PyObject*)newPyStdOut( false ); // stdout
241 _verr=(PyObject*)newPyStdOut( true ); // stderr
243 // All the initRun outputs are redirected to the standard output (console)
247 void PyInterp_Interp::destroy()
254 \brief Initialize Python interpreter.
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
262 void PyInterp_Interp::initPython()
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++)
269 changed_argv[i] = Py_DecodeLocale(_argv[i], NULL);
272 Py_SetProgramName(changed_argv[0]);
273 Py_Initialize(); // Initialize the interpreter
274 PySys_SetArgv(_argc, changed_argv);
276 #if PY_VERSION_HEX < 0x03070000
277 PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
279 PyEval_SaveThread(); // release safely GIL
284 \brief Get embedded Python interpreter banner.
285 \return banner string
287 std::string PyInterp_Interp::getBanner() const
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";
297 \brief Initialize run command.
299 This method is used to prepare interpreter for running
302 \return \c true on success and \c false on error
304 bool PyInterp_Interp::initRun()
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.
316 bool PyInterp_Interp::initContext()
318 PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context)
323 _global_context = PyModule_GetDict(m); // get interpreter global variable context
324 Py_INCREF(_global_context);
325 _local_context = _global_context;
331 * Destroy context dictionaries. GIL is held already.
333 void PyInterp_Interp::closeContext()
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);
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.
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
350 static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
352 PyObject *m = PyImport_AddModule("codeop");
354 // Fatal error. No way to go on.
359 PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
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);
369 else if (v == Py_None) {
370 // Incomplete text we return 1 : we need a complete text to execute
374 PyObjWrapper r(PyEval_EvalCode((PyObject *)(void *)v,global_ctxt, local_ctxt));
376 // Execution error. We return -1
380 // The command has been successfully executed. Return 0
385 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
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'
395 std::vector<std::string>
396 __split(const std::string& str, char delimiter)
398 std::vector<std::string> internal;
399 std::stringstream ss(str); // Turn the string into a stream.
402 while (getline(ss, tok, delimiter)) {
403 internal.push_back(tok);
410 __join(const std::vector<std::string>& v, int begin=0, int 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) {
423 std::vector<std::string>
424 __getArgsList(std::string argsString)
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);
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);
442 std::vector<std::string> extractedArgs;
444 for (int pos = 0; pos < (int)listBeginIndices.size(); ++pos) {
445 int lbeg = listBeginIndices[pos];
446 int lend = listEndIndices[pos];
448 for (int k = start; k < lbeg; ++k)
449 extractedArgs.push_back(x[k]);
450 extractedArgs.push_back(__join(x, lbeg, lend+1));
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;
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.
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
476 static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
478 // First guess if command is execution of a script with args, or a simple Python command
479 QString singleCommand = command;
480 QString commandArgs = "";
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
490 if (commandArgs.isEmpty()) {
491 return run_command(singleCommand.toStdString().c_str(), global_ctxt, local_ctxt);
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);
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
509 int PyInterp_Interp::run(const char *command)
512 int ret = simpleRun(command);
518 * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsibility
519 * to acquire GIL if needed.
521 int PyInterp_Interp::beforeRun()
527 * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsibility
528 * to acquire GIL if needed.
530 int PyInterp_Interp::afterRun()
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
541 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
543 if( addToHistory && strcmp(command,"") != 0 ) {
544 _history.push_back(command);
545 _ith = _history.end();
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!)
555 // Redirect outputs to SALOME Python console before treatment
556 PySys_SetObject((char*)"stderr",_verr);
557 PySys_SetObject((char*)"stdout",_vout);
559 int ier = compile_command(command, _global_context, _local_context);
561 // Outputs are redirected to what they were before
562 PySys_SetObject((char*)"stdout",oldOut);
563 PySys_SetObject((char*)"stderr",oldErr);
569 \brief Get previous command in the commands history.
570 \return previous command
572 const char * PyInterp_Interp::getPrevious()
574 if(_ith != _history.begin()){
576 return (*_ith).c_str();
579 return BEGIN_HISTORY_PY;
583 \brief Get next command in the commands history.
586 const char * PyInterp_Interp::getNext()
588 if(_ith != _history.end()){
591 if (_ith == _history.end())
592 return TOP_HISTORY_PY;
594 return (*_ith).c_str();
598 \brief Set Python standard output device hook.
599 \param cb callback function
600 \param data callback function parameters
602 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
604 ((PyStdOut*)_vout)->_cb=cb;
605 ((PyStdOut*)_vout)->_data=data;
609 \brief Set Python standard error device hook.
610 \param cb callback function
611 \param data callback function parameters
613 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
615 ((PyStdOut*)_verr)->_cb=cb;
616 ((PyStdOut*)_verr)->_data=data;
620 \bried Check if the interpreter is initialized
623 bool PyInterp_Interp::initialized() const