]> SALOME platform Git repositories - modules/shaper.git/blob - src/InitializationPlugin/InitializationPlugin_PyInterp.cpp
Salome HOME
Issue #2052: Modification of parameters don't work (sketch, extrusion)
[modules/shaper.git] / src / InitializationPlugin / InitializationPlugin_PyInterp.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2 /*
3  * InitializationPlugin_PyInterp.cpp
4  *
5  *  Created on: Apr 2, 2015
6  *      Author: sbh
7  */
8
9 #include <InitializationPlugin_PyInterp.h>
10
11 #include <string>
12 #include <stdexcept>
13
14 InitializationPlugin_PyInterp::InitializationPlugin_PyInterp()
15 : PyInterp_Interp()
16 {
17 }
18
19 InitializationPlugin_PyInterp::~InitializationPlugin_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 InitializationPlugin_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> InitializationPlugin_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 InitializationPlugin_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 InitializationPlugin_PyInterp::clearLocalContext()
126 {
127   PyLockWrapper lck;
128   PyDict_Clear(_local_context);
129 }
130
131 double InitializationPlugin_PyInterp::evaluate(const std::string& theExpression,
132                                                std::string& theError)
133 {
134   PyLockWrapper lck; // Acquire GIL until the end of the method
135   PyCompilerFlags aFlags = {CO_FUTURE_DIVISION};
136   aFlags.cf_flags = CO_FUTURE_DIVISION;
137   PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(theExpression.c_str(),
138                                 "<string>", Py_eval_input, &aFlags);
139   if(!anExprCode) {
140     theError = errorMessage();
141     Py_XDECREF(anExprCode);
142     return 0.;
143   }
144
145   PyObject* anEvalResult = PyEval_EvalCode(anExprCode, _global_context, _local_context);
146   if(!anEvalResult) {
147     theError = errorMessage();
148     Py_XDECREF(anExprCode);
149     Py_XDECREF(anEvalResult);
150     return 0.;
151   }
152
153   PyObject* anEvalStrObj = PyObject_Str(anEvalResult);
154   std::string anEvalStr(PyString_AsString(anEvalStrObj));
155   Py_XDECREF(anExprCode);
156   Py_XDECREF(anEvalResult);
157   Py_XDECREF(anEvalStrObj);
158   double result = 0.;
159   try {
160     result = std::stod(anEvalStr);
161   } catch (const std::invalid_argument&) {
162     theError = "Unable to eval " + anEvalStr;
163   }
164
165   return result;
166 }
167
168 std::string InitializationPlugin_PyInterp::errorMessage()
169 {
170   std::string aPyError;
171   if (PyErr_Occurred()) {
172     PyObject *pstr, *ptype, *pvalue, *ptraceback;
173     PyErr_Fetch(&ptype, &pvalue, &ptraceback);
174     PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
175     pstr = PyObject_Str(pvalue);
176     aPyError = std::string(PyString_AsString(pstr));
177     Py_XDECREF(pstr);
178     Py_XDECREF(ptype);
179     Py_XDECREF(pvalue);
180     Py_XDECREF(ptraceback);
181   }
182   return aPyError;
183 }
184
185 bool InitializationPlugin_PyInterp::initContext()
186 {
187   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
188   if(!m){
189     PyErr_Print();
190     return false;
191   }
192   _global_context = PyModule_GetDict(m);          // get interpreter global variable context
193   Py_INCREF(_global_context);
194   _local_context = PyDict_New();
195   Py_INCREF(_local_context);
196
197   return PyRun_SimpleString("from math import *") == 0;
198 }
199
200 void InitializationPlugin_PyInterp::closeContext()
201 {
202   Py_XDECREF(_local_context);
203   PyInterp_Interp::closeContext();
204 }