Salome HOME
61b8cfd3326baf960cb579913b036b652a233aef
[modules/shaper.git] / src / ParametersPlugin / ParametersPlugin_PyInterp.cpp
1 /*
2  * ParametersPlugin_PyInterp.cpp
3  *
4  *  Created on: Apr 2, 2015
5  *      Author: sbh
6  */
7
8 #include <ParametersPlugin_PyInterp.h>
9
10 #include <string>
11
12 ParametersPlugin_PyInterp::ParametersPlugin_PyInterp()
13 : PyInterp_Interp()
14 {
15 }
16
17 ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp()
18 {
19 }
20
21 std::list<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
22 {
23   PyLockWrapper lck; // Acquire GIL until the end of the method
24   std::list<std::string> aResult;
25   PyObject *aCodeopModule = PyImport_AddModule("codeop");
26   if(!aCodeopModule) { // Fatal error. No way to go on.
27     PyErr_Print();
28     return aResult;
29   }
30
31   PyObject *aCodePyObj =
32       PyObject_CallMethod(aCodeopModule, "compile_command", "(s)", theExpression.c_str());
33
34   if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) {
35     Py_XDECREF(aCodePyObj);
36     return aResult;
37   }
38
39   PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj;
40   std::string aCodeName(PyString_AsString(aCodeObj->co_code));
41   // co_names should be tuple, but can be changed in modern versions of python (>2.7.3)
42   if(!PyTuple_Check(aCodeObj->co_names))
43     return aResult;
44   
45   int params_size = PyTuple_Size(aCodeObj->co_names);
46   if (params_size > 0) {
47     for (int i = 0; i < params_size; i++) {
48       PyObject* aParamObj = PyTuple_GetItem(aCodeObj->co_names, i);
49       PyObject* aParamObjStr = PyObject_Str(aParamObj);
50       std::string aParamName(PyString_AsString(aParamObjStr));
51       aResult.push_back(aParamName);
52       Py_XDECREF(aParamObjStr);
53     }
54   }
55   Py_XDECREF(aCodeObj);
56   return aResult;
57 }
58
59 void ParametersPlugin_PyInterp::extendLocalContext(const std::list<std::string>& theParameters)
60 {
61   PyLockWrapper lck; // Acquire GIL until the end of the method
62   if (theParameters.empty())
63     return;
64   std::list<std::string>::const_iterator it = theParameters.begin();
65   for ( ; it != theParameters.cend(); it++) {
66     std::string aParamValue = *it;
67     simpleRun(aParamValue.c_str(), false);
68   }
69 }
70
71
72 double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError)
73 {
74   PyLockWrapper lck; // Acquire GIL until the end of the method
75   PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileString(theExpression.c_str(),
76                                                                "<string>", Py_eval_input);
77   if(!anExprCode) {
78     theError = errorMessage();
79     Py_XDECREF(anExprCode);
80     return 0.;
81   }
82
83   PyObject* anEvalResult = PyEval_EvalCode(anExprCode, _global_context, _local_context);
84   if(!anEvalResult) {
85     theError = errorMessage();
86     Py_XDECREF(anExprCode);
87     Py_XDECREF(anEvalResult);
88     return 0.;
89   }
90
91   PyObject* anEvalStrObj = PyObject_Str(anEvalResult);
92   std::string anEvalStr(PyString_AsString(anEvalStrObj));
93   Py_XDECREF(anExprCode);
94   Py_XDECREF(anEvalResult);
95   Py_XDECREF(anEvalStrObj);
96   double result = 0.;
97   try {
98     result = std::stod(anEvalStr);
99   } catch (const std::invalid_argument&) {
100     theError = "Unable to eval " + anEvalStr;
101   }
102   
103   return result;
104 }
105
106 std::string ParametersPlugin_PyInterp::errorMessage()
107 {
108   std::string aPyError;
109   if (PyErr_Occurred()) {
110     PyObject *pstr, *ptype, *pvalue, *ptraceback;
111     PyErr_Fetch(&ptype, &pvalue, &ptraceback);
112     PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
113     pstr = PyObject_Str(pvalue);
114     aPyError = std::string(PyString_AsString(pstr));
115     Py_XDECREF(pstr);
116     Py_XDECREF(ptype);
117     Py_XDECREF(pvalue);
118     Py_XDECREF(ptraceback);
119   }
120   return aPyError;
121 }
122
123 bool ParametersPlugin_PyInterp::initContext()
124 {
125   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
126   if(!m){
127     PyErr_Print();
128     return false;
129   }
130   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
131   Py_INCREF(_global_context);
132   _local_context = _global_context;
133
134   return PyRun_SimpleString("from math import *") == 0;
135 }