1 // Copyright (C) 2014-2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <InitializationPlugin_PyInterp.h>
22 #include <Locale_Convert.h>
28 InitializationPlugin_PyInterp::InitializationPlugin_PyInterp()
33 InitializationPlugin_PyInterp::~InitializationPlugin_PyInterp()
37 const char* aSearchCode =
39 "class FindName(ast.NodeVisitor):\n"
40 " def __init__(self, name):\n"
42 " def visit_Name(self, node):\n"
43 " if node.id == self.name:\n"
44 " positions.append((node.lineno, node.col_offset))\n"
45 "FindName(name).visit(ast.parse(expression))";
47 // make the expression be correct for the python interpreter even for the
48 // beta=alfa*2 expressions
49 static std::wstring adjustExpression(const std::wstring& theExpression) {
50 std::wstring anExpression = theExpression;
51 if (!anExpression.empty() && anExpression.back() == L'=') {
52 anExpression = anExpression.substr(0, anExpression.length() - 1);
57 std::list<std::pair<int, int> >
58 InitializationPlugin_PyInterp::positions(const std::wstring& theExpression,
59 const std::wstring& theName)
61 PyLockWrapper lck; // Acquire GIL until the end of the method
63 std::list<std::pair<int, int> > aResult;
66 PyObject* aContext = PyDict_New();
67 PyDict_SetItemString(aContext, "__builtins__", PyEval_GetBuiltins());
69 std::wstring anExpression = adjustExpression(theExpression);
70 // extend aContext with variables
71 PyDict_SetItemString(aContext, "expression",
72 PyUnicode_FromWideChar(anExpression.c_str(), anExpression.size()));
73 PyDict_SetItemString(aContext, "name", PyUnicode_FromWideChar(theName.c_str(), theName.size()));
74 PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]"));
76 // run the search code
77 PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext);
78 Py_XDECREF(aExecResult);
80 // receive results from context
81 PyObject* aPositions = PyDict_GetItemString(aContext, "positions");
82 for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) {
83 PyObject* aPosition = PyList_GetItem(aPositions, anIndex);
84 PyObject* aLineNo = PyTuple_GetItem(aPosition, 0);
85 PyObject* aColOffset = PyTuple_GetItem(aPosition, 1);
88 std::pair<int, int>((int)PyLong_AsLong(aLineNo),
89 (int)PyLong_AsLong(aColOffset)));
92 // TODO(spo): after this refCount of the variable is not 0. Is there memory leak?
99 std::list<std::wstring> InitializationPlugin_PyInterp::compile(const std::wstring& theExpression)
101 PyLockWrapper lck; // Acquire GIL until the end of the method
102 std::list<std::wstring> aResult;
103 PyObject *aCodeopModule = PyImport_AddModule("codeop");
104 if(!aCodeopModule) { // Fatal error. No way to go on.
108 // support "variable_name=" expression as "variable_name"
109 std::wstring anExpression = adjustExpression(theExpression);
111 PyObject *aCodePyObj =
112 PyObject_CallMethod(aCodeopModule, (char*)"compile_command", (char*)"(s)",
113 Locale::Convert::toString(anExpression).c_str());
115 if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) {
116 Py_XDECREF(aCodePyObj);
120 PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj;
121 std::string aCodeName(PyBytes_AsString(aCodeObj->co_code));
122 // co_names should be tuple, but can be changed in modern versions of python (>2.7.3)
123 if(!PyTuple_Check(aCodeObj->co_names)) {
127 size_t params_size = PyTuple_Size(aCodeObj->co_names);
128 if (params_size > 0) {
129 for (size_t i = 0; i < params_size; i++) {
130 PyObject* aParamObj = PyTuple_GetItem(aCodeObj->co_names, i);
131 PyObject* aParamObjStr = PyObject_Str(aParamObj);
133 std::wstring aParamName(PyUnicode_AsWideCharString(aParamObjStr, &aSize));
134 aResult.push_back(aParamName);
135 Py_XDECREF(aParamObjStr);
138 Py_XDECREF(aCodeObj);
142 void InitializationPlugin_PyInterp::extendLocalContext(const std::list<std::wstring>& theParameters)
144 PyLockWrapper lck; // Acquire GIL until the end of the method
145 if (theParameters.empty())
147 std::list<std::wstring>::const_iterator it = theParameters.begin();
148 for ( ; it != theParameters.cend(); it++) {
149 std::string aParamValue = Locale::Convert::toString(*it);
150 simpleRun(aParamValue.c_str(), false);
154 void InitializationPlugin_PyInterp::clearLocalContext()
157 PyDict_Clear(_local_context);
160 double InitializationPlugin_PyInterp::evaluate(const std::wstring& theExpression,
161 std::string& theError)
163 // support "variable_name=" expression as "variable_name"
164 std::wstring anExpression = adjustExpression(theExpression);
166 PyLockWrapper lck; // Acquire GIL until the end of the method
167 PyCompilerFlags aFlags = {CO_FUTURE_DIVISION};
168 aFlags.cf_flags = CO_FUTURE_DIVISION;
169 PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(
170 Locale::Convert::toString(anExpression).c_str(),
171 "<string>", Py_eval_input, &aFlags);
173 theError = errorMessage();
174 Py_XDECREF(anExprCode);
178 PyObject* anEvalResult = PyEval_EvalCode((PyObject *)anExprCode, _global_context, _local_context);
180 theError = errorMessage();
181 Py_XDECREF(anExprCode);
182 Py_XDECREF(anEvalResult);
186 PyObject* anEvalStrObj = PyObject_Str(anEvalResult);
187 std::string anEvalStr(PyUnicode_AsUTF8(anEvalStrObj));
188 Py_XDECREF(anExprCode);
189 Py_XDECREF(anEvalResult);
190 Py_XDECREF(anEvalStrObj);
193 // set locale due to the #2485
194 std::string aCurLocale = std::setlocale(LC_NUMERIC, 0);
195 std::setlocale(LC_NUMERIC, "C");
196 result = std::stod(anEvalStr);
197 std::setlocale(LC_NUMERIC, aCurLocale.c_str());
199 catch (const std::invalid_argument&) {
200 theError = "Unable to eval " + anEvalStr;
206 std::string InitializationPlugin_PyInterp::errorMessage()
208 std::string aPyError;
209 if (PyErr_Occurred()) {
210 PyObject *pstr, *ptype, *pvalue, *ptraceback;
211 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
212 PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
213 pstr = PyObject_Str(pvalue);
214 aPyError = std::string(PyUnicode_AsUTF8(pstr));
218 Py_XDECREF(ptraceback);
223 bool InitializationPlugin_PyInterp::initContext()
225 PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context)
230 _global_context = PyModule_GetDict(m); // get interpreter global variable context
231 Py_INCREF(_global_context);
232 _local_context = PyDict_New();
233 Py_INCREF(_local_context);
235 // to avoid "help()" hang in the python console
236 const static char* aHelpTxt = "def help(): print(\"Available modules:\\n"
237 " salome.shaper.model : higher level access to features and data model\\n"
238 " BuildAPI : Build plugin features allowing to build shapes\\n"
239 " ConfigAPI : configuration management: preferences and XML properties\\n"
240 " ConstructionAPI : Construction plugin for auxiliary features creation\\n"
241 " EventsAPI : application events receiving and emitting manager\\n"
242 " ExchangeAPI : Exchange plugin with import/export features\\n"
243 " FeaturesAPI : Features plugin with general 3D features\\n"
244 " GeomAlgoAPI : geometrical algorithms\\n"
245 " GeomAPI : geometrical data structures\\n"
246 " GeomDataAPI : specific geometrical data structures stored in the data model\\n"
247 " ModelAPI : general low-level interface to access data model\\n"
248 " ModelHighAPI : general high-level interface to access data model\\n"
249 " ParametersAPI : Parameters plugin for parameters feature management\\n"
250 " PartSetAPI : PartSet plugin for management Parts features\\n"
251 " SketchAPI : Sketch plugin with all sketch features\")";
253 PyRun_SimpleString(aHelpTxt);
255 return PyRun_SimpleString("from math import *") == 0;
258 void InitializationPlugin_PyInterp::closeContext()
260 Py_XDECREF(_local_context);
261 PyInterp_Interp::closeContext();
264 bool InitializationPlugin_PyInterp::runString(std::string theString)
266 PyLockWrapper lck; // Acquire GIL until the end of the method
267 return PyRun_SimpleString(theString.c_str());