From b2418a13c302e03ed5f80dbdae0cd20f0abd16af Mon Sep 17 00:00:00 2001 From: sbh Date: Mon, 6 Apr 2015 19:20:42 +0300 Subject: [PATCH] Implementation of python expressions evaluation --- CMakeCommon/FindPython.cmake | 13 +- src/Config/CMakeLists.txt | 2 +- src/ModelAPI/CMakeLists.txt | 9 +- src/ParametersPlugin/CMakeLists.txt | 22 ++- .../ParametersPlugin_Parameter.cpp | 39 +++++- .../ParametersPlugin_Parameter.h | 10 ++ .../ParametersPlugin_PyInterp.cpp | 130 ++++++++++++++++++ .../ParametersPlugin_PyInterp.h | 34 +++++ 8 files changed, 240 insertions(+), 19 deletions(-) create mode 100644 src/ParametersPlugin/ParametersPlugin_PyInterp.cpp create mode 100644 src/ParametersPlugin/ParametersPlugin_PyInterp.h diff --git a/CMakeCommon/FindPython.cmake b/CMakeCommon/FindPython.cmake index c5352896e..d48364e67 100644 --- a/CMakeCommon/FindPython.cmake +++ b/CMakeCommon/FindPython.cmake @@ -1,5 +1,7 @@ ## Copyright (C) 2014-20xx CEA/DEN, EDF R&D +UNSET(PYTHON_INCLUDE_DIRS) +UNSET(PYTHON_LIBRARIES) IF(WIN32) IF(CMAKE_BUILD_TYPE STREQUAL "Debug") @@ -12,15 +14,16 @@ ElSE() ENDIF() IF(WIN32) - FILE(TO_CMAKE_PATH "$ENV{PYTHONHOME}/libs/${PYTHON_LIBRARY_FILE}" PYTHON_LIBRARY) + FILE(TO_CMAKE_PATH "$ENV{PYTHONHOME}/libs/${PYTHON_LIBRARY_FILE}" PATH_PYTHON_LIBRARY) ElSE() - FILE(TO_CMAKE_PATH "$ENV{PYTHONHOME}/lib/${PYTHON_LIBRARY_FILE}" PYTHON_LIBRARY) + FILE(TO_CMAKE_PATH "$ENV{PYTHONHOME}/lib/${PYTHON_LIBRARY_FILE}" PATH_PYTHON_LIBRARY) ENDIF() +FILE(TO_CMAKE_PATH $ENV{PYTHON_INCLUDE} PATH_PYTHON_INCLUDE_DIR) + +SET(PYTHON_INCLUDE_DIR ${PATH_PYTHON_INCLUDE_DIR} CACHE PATH "path to where Python.h is found" FORCE) +SET(PYTHON_LIBRARY ${PATH_PYTHON_LIBRARY} CACHE FILEPATH "path to the python library" FORCE) -FILE(TO_CMAKE_PATH $ENV{PYTHON_INCLUDE} PYTHON_INCLUDE_DIR) FIND_PACKAGE(PythonLibs REQUIRED) FIND_PACKAGE(PythonInterp REQUIRED) INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIR}) -#MESSAGE(STATUS "PYTHON_LIBRARIES: " ${PYTHON_LIBRARIES}) -#MESSAGE(STATUS "PYTHON_INCLUDE_DIR: " ${PYTHON_INCLUDE_DIR}) diff --git a/src/Config/CMakeLists.txt b/src/Config/CMakeLists.txt index 591c8489a..0837555e7 100644 --- a/src/Config/CMakeLists.txt +++ b/src/Config/CMakeLists.txt @@ -4,7 +4,7 @@ INCLUDE(Common) INCLUDE(XMLProcessing) INCLUDE_DIRECTORIES (${PROJECT_SOURCE_DIR}/src/Events - ${PYTHON_INCLUDE_DIRS}) + ${PYTHON_INCLUDE_DIR}) SET(PROJECT_HEADERS Config_def.h diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 8d1dc9d98..8bcae17fd 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -80,11 +80,10 @@ ADD_LIBRARY(ModelAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) SET_TARGET_PROPERTIES(ModelAPI PROPERTIES LINKER_LANGUAGE CXX) TARGET_LINK_LIBRARIES(ModelAPI ${PROJECT_LIBRARIES}) -INCLUDE_DIRECTORIES( - ../Config - ../Events - ../GeomAPI - ../GeomAlgoAPI +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Config + ${PROJECT_SOURCE_DIR}/src/Events + ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ) diff --git a/src/ParametersPlugin/CMakeLists.txt b/src/ParametersPlugin/CMakeLists.txt index 287e84b23..f6e54ea57 100644 --- a/src/ParametersPlugin/CMakeLists.txt +++ b/src/ParametersPlugin/CMakeLists.txt @@ -1,32 +1,42 @@ INCLUDE(Common) - -INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events - ${PROJECT_SOURCE_DIR}/src/Config - ${PROJECT_SOURCE_DIR}/src/ModelAPI -) +INCLUDE(FindPython) SET(PROJECT_HEADERS ParametersPlugin.h ParametersPlugin_Plugin.h ParametersPlugin_Parameter.h + ParametersPlugin_PyInterp.h ) SET(PROJECT_SOURCES ParametersPlugin_Plugin.cpp ParametersPlugin_Parameter.cpp + ParametersPlugin_PyInterp.cpp ) SET(XML_RESOURCES plugin-Parameters.xml ) +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events + ${PROJECT_SOURCE_DIR}/src/Config + ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${SUIT_INCLUDE} + ${PYTHON_INCLUDE_DIR} +) + +MESSAGE(STATUS "PYTHON_LIBRARIES (ParametersPlugin): ${PYTHON_LIBRARIES}") + SET(PROJECT_LIBRARIES Events Config ModelAPI + ${PyInterp} + ${PYTHON_LIBRARIES} ) -ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS) +ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS -DHAVE_DEBUG_PYTHON) ADD_LIBRARY(ParametersPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES}) TARGET_LINK_LIBRARIES(ParametersPlugin ${PROJECT_LIBRARIES}) diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp index c3d72d272..745d0c765 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp @@ -5,18 +5,53 @@ // Author: sbh #include "ParametersPlugin_Parameter.h" +#include + #include +#include +#include + ParametersPlugin_Parameter::ParametersPlugin_Parameter() { + myInterp = new ParametersPlugin_PyInterp(); + myInterp->initialize(); +} + +ParametersPlugin_Parameter::~ParametersPlugin_Parameter() +{ + delete myInterp; } void ParametersPlugin_Parameter::initAttributes() { - data()->addAttribute(ParametersPlugin_Parameter::VARIABLE_ID(), ModelAPI_AttributeString::typeId()); - data()->addAttribute(ParametersPlugin_Parameter::EXPRESSION_ID(), ModelAPI_AttributeString::typeId()); + data()->addAttribute(ParametersPlugin_Parameter::VARIABLE_ID(), + ModelAPI_AttributeString::typeId()); + data()->addAttribute(ParametersPlugin_Parameter::EXPRESSION_ID(), + ModelAPI_AttributeString::typeId()); } void ParametersPlugin_Parameter::execute() { + std::string anExpression = string(ParametersPlugin_Parameter::EXPRESSION_ID())->value(); + if(anExpression.empty()) + return; + ResultParameterPtr aParameterResult = document()->createParameter(data()); + //AttributeDoublePtr anAttr = aParameterResult->data()->real(ModelAPI_ResultParameter::VALUE()); + + double aValue = evaluate(anExpression); + //anAttr->setValue(aValue); + setResult(aParameterResult); + +} + +double ParametersPlugin_Parameter::evaluate(std::string theExpression) +{ + std::list anExprParams = myInterp->compile(theExpression); + // find expression's params in the model + // todo + // myInterp->extendLocalContext(); + std::string outError; + return myInterp->evaluate(theExpression, outError); + } diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.h b/src/ParametersPlugin/ParametersPlugin_Parameter.h index e7574fd2a..66cd99bfa 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.h +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.h @@ -10,9 +10,13 @@ #include "ParametersPlugin.h" #include +class ParametersPlugin_PyInterp; + class ParametersPlugin_Parameter : public ModelAPI_Feature { public: + virtual ~ParametersPlugin_Parameter(); + /// Extrusion kind inline static const std::string& ID() { @@ -49,6 +53,12 @@ class ParametersPlugin_Parameter : public ModelAPI_Feature /// Use plugin manager for features creation ParametersPlugin_Parameter(); + + protected: + double evaluate(std::string); + + private: + ParametersPlugin_PyInterp* myInterp; }; #endif diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp new file mode 100644 index 000000000..92812f50a --- /dev/null +++ b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp @@ -0,0 +1,130 @@ +/* + * ParametersPlugin_PyInterp.cpp + * + * Created on: Apr 2, 2015 + * Author: sbh + */ + +#include + +#include + +ParametersPlugin_PyInterp::ParametersPlugin_PyInterp() +: PyInterp_Interp() +{ +} + +ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp() +{ +} + +std::list ParametersPlugin_PyInterp::compile(const std::string& theExpression) +{ + PyGILState_STATE aGilState = PyGILState_Ensure(); + std::list res = this->_compile(theExpression); + PyGILState_Release(aGilState); + return res; +} + +void ParametersPlugin_PyInterp::extendLocalContext(const std::list& theParameters) +{ + PyGILState_STATE aGilState = PyGILState_Ensure(); + this->_extendLocalContext(theParameters); + PyGILState_Release(aGilState); +} + +double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, + std::string& theError) +{ + PyGILState_STATE aGilState = PyGILState_Ensure(); + double res = this->_evaluate(theExpression, theError); + PyGILState_Release(aGilState); + return res; +} + + +std::list ParametersPlugin_PyInterp::_compile(const std::string& theExpression) +{ + + std::list aResult; + PyObject *aCodeopModule = PyImport_AddModule("codeop"); + if(!aCodeopModule) { // Fatal error. No way to go on. + PyErr_Print(); + return aResult; + } + + PyObject *aCodePyObj = + PyObject_CallMethod(aCodeopModule, "compile_command", "(s)", theExpression.c_str()); + + if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) { + Py_XDECREF(aCodePyObj); + return aResult; + } + + PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj; + // co_names should be tuple, but can be changed in modern versions of python (>2.7.3) + if(!PyTuple_Check(aCodeObj->co_names)) + return aResult; + + int params_size = PyTuple_Size(aCodeObj->co_names); + if (params_size > 0) { + for (int i = 0; i < params_size; i++) { + PyObject* aParamObj = PyTuple_GetItem(aCodeObj->co_names, i); + PyObject* aParamObjStr = PyObject_Str(aParamObj); + std::string aParamName(PyString_AsString(aParamObjStr)); + aResult.push_back(aParamName); + Py_XDECREF(aParamObjStr); + } + } + Py_XDECREF(aCodeObj); + return aResult; +} + +void ParametersPlugin_PyInterp::_extendLocalContext(const std::list& theParameters) +{ + if (theParameters.empty()) + return; +} + + +double ParametersPlugin_PyInterp::_evaluate(const std::string& theExpression, std::string& theError) +{ + PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileString(theExpression.c_str(), + "", Py_eval_input); + if(!anExprCode) { + theError = errorMessage(); + Py_XDECREF(anExprCode); + return 0.; + } + + PyObject* anEvalResult = PyEval_EvalCode(anExprCode, _global_context, _local_context); + if(!anEvalResult) { + theError = errorMessage(); + Py_XDECREF(anExprCode); + Py_XDECREF(anEvalResult); + return 0.; + } + + PyObject* anEvalStrObj = PyObject_Str(anEvalResult); + std::string anEvalStr(PyString_AsString(anEvalStrObj)); + double result = std::stod(anEvalStr); + + return result; +} + +std::string ParametersPlugin_PyInterp::errorMessage() +{ + std::string aPyError; + if (PyErr_Occurred()) { + PyObject *pstr, *ptype, *pvalue, *ptraceback; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); + pstr = PyObject_Str(pvalue); + aPyError = std::string(PyString_AsString(pstr)); + Py_XDECREF(pstr); + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + } + return aPyError; +} diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.h b/src/ParametersPlugin/ParametersPlugin_PyInterp.h new file mode 100644 index 000000000..6bb2a210d --- /dev/null +++ b/src/ParametersPlugin/ParametersPlugin_PyInterp.h @@ -0,0 +1,34 @@ +/* + * ParametersPlugin_PyInterp.h + * + * Created on: Apr 2, 2015 + * Author: sbh + */ + +#ifndef PARAMETERSPLUGIN_PYINTERP_H_ +#define PARAMETERSPLUGIN_PYINTERP_H_ + +#include +#include + +#include +#include + +class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp +{ + public: + ParametersPlugin_PyInterp(); + virtual ~ParametersPlugin_PyInterp(); + + std::list compile(const std::string&); + void extendLocalContext(const std::list&); + double evaluate(const std::string&, std::string&); + + protected: + std::list _compile(const std::string&); + void _extendLocalContext(const std::list&); + double _evaluate(const std::string&, std::string&); + std::string errorMessage(); +}; + +#endif /* PARAMETERSPLUGIN_PYINTERP_H_ */ -- 2.39.2