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