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