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