1 // Copyright (C) 2007-2023 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 #if PY_VERSION_HEX < 0x03080000
273 Py_SetProgramName(changed_argv[0]);
274 Py_Initialize(); // Initialize the interpreter
275 PySys_SetArgv(_argc, changed_argv);
278 PyConfig_InitPythonConfig(&config);
279 PyStatus status = PyConfig_SetString(&config, &config.program_name, changed_argv[0]);
280 status = PyConfig_SetArgv(&config, _argc, changed_argv);
281 status = Py_InitializeFromConfig(&config);
282 PyConfig_Clear(&config);
285 #if PY_VERSION_HEX < 0x03070000
286 PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL)
288 PyEval_SaveThread(); // release safely GIL
293 \brief Get embedded Python interpreter banner.
294 \return banner string
296 std::string PyInterp_Interp::getBanner() const
299 std::string aBanner("Python ");
300 aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
301 aBanner = aBanner + "\ntype help to get general information on environment\n";
306 \brief Initialize run command.
308 This method is used to prepare interpreter for running
311 \return \c true on success and \c false on error
313 bool PyInterp_Interp::initRun()
319 * Initialize context dictionaries. GIL is held already.
320 * The code executed in an embedded interpreter is expected to be run at the module
321 * level, in which case local and global context have to be the same dictionary.
322 * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context
323 * for an explanation.
325 bool PyInterp_Interp::initContext()
327 PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context)
332 _global_context = PyModule_GetDict(m); // get interpreter global variable context
333 Py_INCREF(_global_context);
334 _local_context = _global_context;
340 * Destroy context dictionaries. GIL is held already.
342 void PyInterp_Interp::closeContext()
344 Py_XDECREF(_global_context);
345 // both _global_context and _local_context may point to the same Python object
346 if ( _global_context != _local_context)
347 Py_XDECREF(_local_context);
351 \brief Compile Python command and evaluate it in the
352 python dictionary contexts if possible. This is not thread-safe.
353 This is the caller's responsibility to make this thread-safe.
355 \param command Python command string
356 \return -1 on fatal error, 1 if command is incomplete and 0
357 if command is executed successfully
359 static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
361 PyObject *m = PyImport_AddModule("codeop");
363 // Fatal error. No way to go on.
368 PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command));
370 // Error encountered. It should be SyntaxError,
371 //so we don't write out traceback
372 PyObjWrapper exception, value, tb;
373 PyErr_Fetch(&exception, &value, &tb);
374 PyErr_NormalizeException(&exception, &value, &tb);
375 PyErr_Display(exception, value, NULL);
378 else if (v == Py_None) {
379 // Incomplete text we return 1 : we need a complete text to execute
383 PyObjWrapper r(PyEval_EvalCode((PyObject *)(void *)v,global_ctxt, local_ctxt));
385 // Execution error. We return -1
389 // The command has been successfully executed. Return 0
394 void replaceAll(std::string& str, const std::string& from, const std::string& to) {
397 size_t start_pos = 0;
398 while((start_pos = str.find(from, start_pos)) != std::string::npos) {
399 str.replace(start_pos, from.length(), to);
400 start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
404 std::vector<std::string>
405 __split(const std::string& str, char delimiter)
407 std::vector<std::string> internal;
408 std::stringstream ss(str); // Turn the string into a stream.
411 while (getline(ss, tok, delimiter)) {
412 internal.push_back(tok);
419 __join(const std::vector<std::string>& v, int begin=0, int end=-1)
422 end = (int)v.size(); //!< TODO: conversion from size_t to int
423 std::stringstream ss;
424 for (int i = begin; i < end; ++i) {
432 std::vector<std::string>
433 __getArgsList(std::string argsString)
435 // Special process if some items of 'args:' list are themselves lists
436 // Note that an item can be a list, but not a list of lists...
437 // So we can have something like this:
438 // myscript.py args:[\'file1\',\'file2\'],\'val1\',\"done\",[1,2,3],[True,False],\"ok\",kwarg1=\'kwarg1\',kwarg2=\'kwarg2\',\'fin\'
439 // 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'
440 // We have to split argsString to obtain a 9 string elements list
441 std::vector<std::string> x = __split(argsString, ',');
442 bool containsList = (argsString.find('[') != std::string::npos);
444 std::vector<int> listBeginIndices, listEndIndices;
445 for (int pos = 0; pos < (int)x.size(); ++pos) {
446 if (x[pos][0] == '[')
447 listBeginIndices.push_back(pos);
448 else if (x[pos][x[pos].size()-1] == ']')
449 listEndIndices.push_back(pos);
451 std::vector<std::string> extractedArgs;
453 for (int pos = 0; pos < (int)listBeginIndices.size(); ++pos) {
454 int lbeg = listBeginIndices[pos];
455 int lend = listEndIndices[pos];
457 for (int k = start; k < lbeg; ++k)
458 extractedArgs.push_back(x[k]);
459 extractedArgs.push_back(__join(x, lbeg, lend+1));
462 if (start < (int)x.size())
463 for (int k = start; k < (int)x.size(); ++k)
464 extractedArgs.push_back(x[k]);
465 return extractedArgs;
473 \brief Compile Python command and evaluate it in the
474 python dictionary context if possible. Command might correspond to
475 the execution of a script with optional arguments.
476 In this case, command is:
477 exec(open(r"/absolute/path/to/script.py", "rb").read(), args=(arg1,...,argn))
478 and args parameter is optional one. This parameter is specified as a tuple of strings.
480 \param command Python command string
481 \param context Python context (dictionary)
482 \return -1 on fatal error, 1 if command is incomplete and 0
483 if command is executed successfully
485 static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt)
487 // First guess if command is execution of a script with args, or a simple Python command
488 QString singleCommand = command;
489 QString commandArgs = "";
491 QRegularExpression rx("exec\\s*\\(.*open\\s*\\(\\s*(.*)\\s*\\)\\s*\\.\\s*read\\s*\\(\\)(\\s*,\\s*args\\s*=\\s*\\(.*\\))\\s*\\)");
492 QRegularExpressionMatch match = rx.match(command);
493 if (match.hasMatch()) {
494 commandArgs = match.captured(2).remove(0, match.captured(2).indexOf("(")); // arguments of command
495 commandArgs.insert(commandArgs.indexOf('(')+1, match.captured(1).split(",")[0].trimmed() + ","); // prepend arguments list by the script file itself
496 singleCommand = singleCommand.remove(match.capturedStart(2), match.captured(2).size()); // command for execution without arguments
499 if (commandArgs.isEmpty()) {
500 return run_command(singleCommand.toStdString().c_str(), global_ctxt, local_ctxt);
503 ///////////////std::vector<std::string> argList = __getArgsList(commandArgs);
504 QString preCommandBegin = "import sys; save_argv = sys.argv; sys.argv=list(";
505 QString preCommandEnd = ");";
506 QString postCommand = ";sys.argv=save_argv";
507 QString completeCommand = preCommandBegin+commandArgs+preCommandEnd+singleCommand.trimmed()+postCommand;
508 return run_command(completeCommand.toStdString().c_str(), global_ctxt, local_ctxt);
513 \brief Run Python command - the command has to fit on a single line (no \n!).
514 Use ';' if you need multiple statements evaluated at once.
515 \param command Python command
516 \return command status
518 int PyInterp_Interp::run(const char *command)
521 int ret = simpleRun(command);
527 * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsibility
528 * to acquire GIL if needed.
530 int PyInterp_Interp::beforeRun()
536 * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsibility
537 * to acquire GIL if needed.
539 int PyInterp_Interp::afterRun()
545 \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsibility.
546 \param command Python command
547 \param addToHistory if \c true (default), the command is added to the commands history
548 \return command status
550 int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory)
552 if( addToHistory && strcmp(command,"") != 0 ) {
553 _history.push_back(command);
554 _ith = _history.end();
557 // Current stdout and stderr are saved
558 PyObject * oldOut = PySys_GetObject((char*)"stdout");
559 PyObject * oldErr = PySys_GetObject((char*)"stderr");
560 // Keep them alive (PySys_GetObject returned a *borrowed* ref!)
564 // Redirect outputs to SALOME Python console before treatment
565 PySys_SetObject((char*)"stderr",_verr);
566 PySys_SetObject((char*)"stdout",_vout);
568 int ier = compile_command(command, _global_context, _local_context);
570 // Outputs are redirected to what they were before
571 PySys_SetObject((char*)"stdout",oldOut);
572 PySys_SetObject((char*)"stderr",oldErr);
578 \brief Get previous command in the commands history.
579 \return previous command
581 const char * PyInterp_Interp::getPrevious()
583 if(_ith != _history.begin()){
585 return (*_ith).c_str();
588 return BEGIN_HISTORY_PY;
592 \brief Get next command in the commands history.
595 const char * PyInterp_Interp::getNext()
597 if(_ith != _history.end()){
600 if (_ith == _history.end())
601 return TOP_HISTORY_PY;
603 return (*_ith).c_str();
607 \brief Set Python standard output device hook.
608 \param cb callback function
609 \param data callback function parameters
611 void PyInterp_Interp::setvoutcb(PyOutChanged* cb, void* data)
613 ((PyStdOut*)_vout)->_cb=cb;
614 ((PyStdOut*)_vout)->_data=data;
618 \brief Set Python standard error device hook.
619 \param cb callback function
620 \param data callback function parameters
622 void PyInterp_Interp::setverrcb(PyOutChanged* cb, void* data)
624 ((PyStdOut*)_verr)->_cb=cb;
625 ((PyStdOut*)_verr)->_data=data;
629 \bried Check if the interpreter is initialized
632 bool PyInterp_Interp::initialized() const