Salome HOME
054c8c3e2bdbe1b209c381d7f10551f928dd5c6d
[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 const char* aSearchCode =
23   "import ast\n"
24   "class FindName(ast.NodeVisitor):\n"
25   "    def __init__(self, name):\n"
26   "        self.name = name\n"
27   "    def visit_Name(self, node):\n"
28   "        if node.id == self.name:\n"
29   "            positions.append((node.lineno, node.col_offset))\n"
30   "FindName(name).visit(ast.parse(expression))";
31
32 std::list<std::pair<int, int> >
33 ParametersPlugin_PyInterp::positions(const std::string& theExpression,
34                                      const std::string& theName)
35 {
36   PyLockWrapper lck; // Acquire GIL until the end of the method
37
38   std::list<std::pair<int, int> > aResult;
39
40   // prepare a context
41   PyObject* aContext = PyDict_New();
42   PyObject* aBuiltinModule = PyImport_AddModule("__builtin__");
43   PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule);
44
45   // extend aContext with variables 
46   PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str()));
47   PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str()));
48   PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]"));
49
50   // run the search code
51   PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext);
52   Py_XDECREF(aExecResult);
53
54   // receive results from context
55   PyObject* aPositions = PyDict_GetItemString(aContext, "positions");
56   for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) {
57     PyObject* aPosition = PyList_GetItem(aPositions, anIndex);
58     PyObject* aLineNo = PyTuple_GetItem(aPosition, 0);
59     PyObject* aColOffset = PyTuple_GetItem(aPosition, 1);
60
61     aResult.push_back(
62         std::pair<int, int>((int)PyInt_AsLong(aLineNo),
63                             (int)PyInt_AsLong(aColOffset)));
64   }
65
66   // TODO(spo): after this refCount of the variable is not 0. Is there memory leak?
67   Py_DECREF(aContext);
68
69   return aResult;
70 }
71
72
73 std::list<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
74 {
75   PyLockWrapper lck; // Acquire GIL until the end of the method
76   std::list<std::string> aResult;
77   PyObject *aCodeopModule = PyImport_AddModule("codeop");
78   if(!aCodeopModule) { // Fatal error. No way to go on.
79     PyErr_Print();
80     return aResult;
81   }
82
83   PyObject *aCodePyObj =
84       PyObject_CallMethod(aCodeopModule, (char*)"compile_command", (char*)"(s)", theExpression.c_str());
85
86   if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) {
87     Py_XDECREF(aCodePyObj);
88     return aResult;
89   }
90
91   PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj;
92   std::string aCodeName(PyString_AsString(aCodeObj->co_code));
93   // co_names should be tuple, but can be changed in modern versions of python (>2.7.3)
94   if(!PyTuple_Check(aCodeObj->co_names))
95     return aResult;
96
97   int params_size = PyTuple_Size(aCodeObj->co_names);
98   if (params_size > 0) {
99     for (int i = 0; i < params_size; i++) {
100       PyObject* aParamObj = PyTuple_GetItem(aCodeObj->co_names, i);
101       PyObject* aParamObjStr = PyObject_Str(aParamObj);
102       std::string aParamName(PyString_AsString(aParamObjStr));
103       aResult.push_back(aParamName);
104       Py_XDECREF(aParamObjStr);
105     }
106   }
107   Py_XDECREF(aCodeObj);
108   return aResult;
109 }
110
111 void ParametersPlugin_PyInterp::extendLocalContext(const std::list<std::string>& theParameters)
112 {
113   PyLockWrapper lck; // Acquire GIL until the end of the method
114   if (theParameters.empty())
115     return;
116   std::list<std::string>::const_iterator it = theParameters.begin();
117   for ( ; it != theParameters.cend(); it++) {
118     std::string aParamValue = *it;
119     simpleRun(aParamValue.c_str(), false);
120   }
121 }
122
123 void ParametersPlugin_PyInterp::clearLocalContext()
124 {
125   PyLockWrapper lck;
126   PyDict_Clear(_local_context);
127 }
128
129
130 double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError)
131 {
132   PyLockWrapper lck; // Acquire GIL until the end of the method
133   PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileString(theExpression.c_str(),
134                                                                "<string>", Py_eval_input);
135   if(!anExprCode) {
136     theError = errorMessage();
137     Py_XDECREF(anExprCode);
138     return 0.;
139   }
140
141   PyObject* anEvalResult = PyEval_EvalCode(anExprCode, _global_context, _local_context);
142   if(!anEvalResult) {
143     theError = errorMessage();
144     Py_XDECREF(anExprCode);
145     Py_XDECREF(anEvalResult);
146     return 0.;
147   }
148
149   PyObject* anEvalStrObj = PyObject_Str(anEvalResult);
150   std::string anEvalStr(PyString_AsString(anEvalStrObj));
151   Py_XDECREF(anExprCode);
152   Py_XDECREF(anEvalResult);
153   Py_XDECREF(anEvalStrObj);
154   double result = 0.;
155   try {
156     result = std::stod(anEvalStr);
157   } catch (const std::invalid_argument&) {
158     theError = "Unable to eval " + anEvalStr;
159   }
160   
161   return result;
162 }
163
164 std::string ParametersPlugin_PyInterp::errorMessage()
165 {
166   std::string aPyError;
167   if (PyErr_Occurred()) {
168     PyObject *pstr, *ptype, *pvalue, *ptraceback;
169     PyErr_Fetch(&ptype, &pvalue, &ptraceback);
170     PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
171     pstr = PyObject_Str(pvalue);
172     aPyError = std::string(PyString_AsString(pstr));
173     Py_XDECREF(pstr);
174     Py_XDECREF(ptype);
175     Py_XDECREF(pvalue);
176     Py_XDECREF(ptraceback);
177   }
178   return aPyError;
179 }
180
181 bool ParametersPlugin_PyInterp::initContext()
182 {
183   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
184   if(!m){
185     PyErr_Print();
186     return false;
187   }
188   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
189   Py_INCREF(_global_context);
190   _local_context = PyDict_New();
191   Py_INCREF(_local_context);
192
193   return PyRun_SimpleString("from math import *") == 0;
194 }
195
196 void ParametersPlugin_PyInterp::closeContext()
197 {
198   Py_XDECREF(_local_context);
199   PyInterp_Interp::closeContext();
200 }