From: mpv Date: Wed, 23 Nov 2016 09:39:26 +0000 (+0300) Subject: Issue #1806 : evaluation of expressions if no parameters defined. X-Git-Tag: V_2.6.0~69 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=332f6b9a2a68158cf49feab94e21dd384d144b37;p=modules%2Fshaper.git Issue #1806 : evaluation of expressions if no parameters defined. Now the python interpreter is loaded in Initialization plugin and accessible for any expression evaluation even if no parameters were created. --- diff --git a/src/InitializationPlugin/CMakeLists.txt b/src/InitializationPlugin/CMakeLists.txt index 7967fcc67..e5b0ce86b 100644 --- a/src/InitializationPlugin/CMakeLists.txt +++ b/src/InitializationPlugin/CMakeLists.txt @@ -1,36 +1,44 @@ - INCLUDE(Common) +INCLUDE(FindPython) INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/ModelAPI ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomDataAPI + ${PROJECT_SOURCE_DIR}/src/ParametersPlugin + ${SUIT_INCLUDE} + ${PYTHON_INCLUDE_DIR} ) SET(PROJECT_HEADERS InitializationPlugin.h InitializationPlugin_Plugin.h - #InitializationPlugin_OriginPlanesFeature.h + InitializationPlugin_EvalListener.h + InitializationPlugin_PyInterp.h ) SET(PROJECT_SOURCES InitializationPlugin_Plugin.cpp - #InitializationPlugin_OriginPlanesFeature.cpp + InitializationPlugin_EvalListener.cpp + InitializationPlugin_PyInterp.cpp ) -#SET(XML_RESOURCES -#) +MESSAGE(STATUS "PYTHON_LIBRARIES (ParametersPlugin): ${PYTHON_LIBRARIES}") SET(PROJECT_LIBRARIES Events Config ModelAPI + ${PyInterp} + ${PYTHON_LIBRARIES} ) -ADD_DEFINITIONS(-DINITIALIZATIONPLUGIN_EXPORTS) +ADD_DEFINITIONS(-DINITIALIZATIONPLUGIN_EXPORTS -DHAVE_DEBUG_PYTHON) ADD_LIBRARY(InitializationPlugin MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${XML_RESOURCES}) TARGET_LINK_LIBRARIES(InitializationPlugin ${PROJECT_LIBRARIES}) INSTALL(TARGETS InitializationPlugin DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) #INSTALL(FILES ${XML_RESOURCES} DESTINATION plugins) + diff --git a/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp new file mode 100644 index 000000000..86d457a73 --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_EvalListener.cpp @@ -0,0 +1,210 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +/* + * InitializationPlugin_EvalListener.cpp + * + * Created on: Apr 28, 2015 + * Author: sbh + */ + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +//------------------------------------------------------------------------------ +// Tools + +std::string toStdString(double theValue) +{ + std::ostringstream sstream; + sstream << theValue; + size_t aPos = sstream.str().find("."); + std::string aPnt = ""; + if (aPos == std::string::npos) + aPnt = "."; + return sstream.str() + aPnt; +} + +std::set toSet(const std::list& theContainer) +{ + return std::set(theContainer.begin(), theContainer.end()); +} + +//------------------------------------------------------------------------------ + +InitializationPlugin_EvalListener::InitializationPlugin_EvalListener() +{ + Events_Loop* aLoop = Events_Loop::loop(); + + aLoop->registerListener(this, ModelAPI_AttributeEvalMessage::eventId(), NULL, true); + aLoop->registerListener(this, ModelAPI_ParameterEvalMessage::eventId(), NULL, true); + aLoop->registerListener(this, ModelAPI_ComputePositionsMessage::eventId(), NULL, true); + + myInterp = std::shared_ptr(new InitializationPlugin_PyInterp()); + myInterp->initialize(); +} + +InitializationPlugin_EvalListener::~InitializationPlugin_EvalListener() +{ +} + +void InitializationPlugin_EvalListener::processEvent( + const std::shared_ptr& theMessage) +{ + if (!theMessage.get()) + return; + + if (theMessage->eventID() == ModelAPI_AttributeEvalMessage::eventId()) { + processEvaluationEvent(theMessage); + } else if (theMessage->eventID() == ModelAPI_ParameterEvalMessage::eventId()) { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + FeaturePtr aParam = aMsg->parameter(); + std::string anExp = aParam->string(ParametersPlugin_Parameter::EXPRESSION_ID())->value(); + std::string anError; + std::list > aParamsList; + double aResult = evaluate(aParam, anExp, anError, aParamsList, true); + aMsg->setResults(aParamsList, aResult, anError); + } else if (theMessage->eventID() == ModelAPI_ComputePositionsMessage::eventId()) { + std::shared_ptr aMsg = + std::dynamic_pointer_cast(theMessage); + aMsg->setPositions(myInterp->positions(aMsg->expression(), aMsg->parameter())); + } +} + +double InitializationPlugin_EvalListener::evaluate(FeaturePtr theParameter, + const std::string& theExpression, std::string& theError, + std::list >& theParamsList, + const bool theIsParameter) +{ + std::list anExprParams = myInterp->compile(theExpression); + // find expression's params in the model + std::list aContext; + std::list::iterator it = anExprParams.begin(); + for ( ; it != anExprParams.end(); it++) { + double aValue; + ResultParameterPtr aParamRes; + // If variable does not exist python interpreter will generate an error. It is OK. + // But due to the issue 1479 it should not check the history position of parameters relatively + // to feature that contains expression + if (!ModelAPI_Tools::findVariable(theIsParameter ? theParameter : FeaturePtr(), + *it, aValue, aParamRes, theParameter->document())) + continue; + + if (theIsParameter) + theParamsList.push_back(aParamRes); + aContext.push_back(*it + "=" + toStdString(aValue)); + } + myInterp->extendLocalContext(aContext); + double result = myInterp->evaluate(theExpression, theError); + myInterp->clearLocalContext(); + return result; +} + +void InitializationPlugin_EvalListener::processEvaluationEvent( + const std::shared_ptr& theMessage) +{ + std::shared_ptr aMessage = + std::dynamic_pointer_cast(theMessage); + + std::list > aParamsList; + FeaturePtr aParamFeature = + std::dynamic_pointer_cast(aMessage->attribute()->owner()); + if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) { + AttributeIntegerPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string anError; + int aValue = (int)evaluate(aParamFeature, anAttribute->text(), anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) + anAttribute->setCalculatedValue(aValue); + anAttribute->setUsedParameters(isValid ? + toSet(myInterp->compile(anAttribute->text())) : std::set()); + anAttribute->setExpressionInvalid(!isValid); + anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); + } else + if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) { + AttributeDoublePtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string anError; + double aValue = evaluate(aParamFeature, anAttribute->text(), anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) + anAttribute->setCalculatedValue(aValue); + anAttribute->setUsedParameters(isValid ? + toSet(myInterp->compile(anAttribute->text())) : std::set()); + anAttribute->setExpressionInvalid(!isValid); + anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); + } else + if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) { + AttributePointPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string aText[] = { + anAttribute->textX(), + anAttribute->textY(), + anAttribute->textZ() + }; + double aCalculatedValue[] = { + anAttribute->x(), + anAttribute->y(), + anAttribute->z() + }; + for (int i = 0; i < 3; ++i) { + std::string anError; + double aValue = evaluate(aParamFeature, aText[i], anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) aCalculatedValue[i] = aValue; + anAttribute->setUsedParameters(i, + isValid ? toSet(myInterp->compile(aText[i])) : std::set()); + anAttribute->setExpressionInvalid(i, !isValid); + anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); + } + anAttribute->setCalculatedValue(aCalculatedValue[0], + aCalculatedValue[1], + aCalculatedValue[2]); + } else + if (aMessage->attribute()->attributeType() == GeomDataAPI_Point2D::typeId()) { + AttributePoint2DPtr anAttribute = + std::dynamic_pointer_cast(aMessage->attribute()); + std::string aText[] = { + anAttribute->textX(), + anAttribute->textY() + }; + double aCalculatedValue[] = { + anAttribute->x(), + anAttribute->y() + }; + for (int i = 0; i < 2; ++i) { + std::string anError; + double aValue = evaluate(aParamFeature, aText[i], anError, aParamsList); + bool isValid = anError.empty(); + if (isValid) aCalculatedValue[i] = aValue; + anAttribute->setUsedParameters(i, + isValid ? toSet(myInterp->compile(aText[i])) : std::set()); + anAttribute->setExpressionInvalid(i, !isValid); + anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); + } + anAttribute->setCalculatedValue(aCalculatedValue[0], + aCalculatedValue[1]); + } +} diff --git a/src/InitializationPlugin/InitializationPlugin_EvalListener.h b/src/InitializationPlugin/InitializationPlugin_EvalListener.h new file mode 100644 index 000000000..9ddb19dda --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_EvalListener.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +/* + * InitializationPlugin_EvalListener.h + * + * Created on: Apr 28, 2015 + * Author: sbh + */ + +#ifndef SRC_INITIALIZATIONPLUGIN_EVALLISTENER_H_ +#define SRC_INITIALIZATIONPLUGIN_EVALLISTENER_H_ + +#include +#include + +class ModelAPI_Attribute; +class ModelAPI_Document; +class ModelAPI_Feature; +class ModelAPI_ResultParameter; +class InitializationPlugin_Parameter; +class InitializationPlugin_PyInterp; + +/** + * \class InitializationPlugin_EvalListener + * \ingroup Plugins + * \brief Class which process the events from the event loop. + */ +class InitializationPlugin_EvalListener : public Events_Listener +{ + public: + INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_EvalListener(); + INITIALIZATIONPLUGIN_EXPORT virtual ~InitializationPlugin_EvalListener(); + + /// Reimplemented from Events_Listener::processEvent(). + INITIALIZATIONPLUGIN_EXPORT + virtual void processEvent(const std::shared_ptr& theMessage); + + protected: + /// Evaluates theExpression and returns its value. + double evaluate(std::shared_ptr theParameter, + const std::string& theExpression, std::string& theError, + std::list >& theParamsList, + const bool theIsParameter = false); + + /// Processes Evaluation event. + void processEvaluationEvent(const std::shared_ptr& theMessage); + + private: + std::shared_ptr myInterp; +}; + +#endif /* SRC_INITIALIZATIONPLUGIN_INITIALIZATIONPLUGIN_EVALLISTENER_H_ */ diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp index ee76b04d2..5367ef276 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.cpp +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -25,6 +26,9 @@ InitializationPlugin_Plugin::InitializationPlugin_Plugin() Events_Loop* aLoop = Events_Loop::loop(); const Events_ID kDocCreatedEvent = ModelAPI_DocumentCreatedMessage::eventId(); aLoop->registerListener(this, kDocCreatedEvent, NULL, true); + + myEvalListener = + std::shared_ptr(new InitializationPlugin_EvalListener()); } void InitializationPlugin_Plugin::processEvent(const std::shared_ptr& theMessage) diff --git a/src/InitializationPlugin/InitializationPlugin_Plugin.h b/src/InitializationPlugin/InitializationPlugin_Plugin.h index 6f06f059f..52d5cc3e9 100644 --- a/src/InitializationPlugin/InitializationPlugin_Plugin.h +++ b/src/InitializationPlugin/InitializationPlugin_Plugin.h @@ -4,11 +4,12 @@ #define INITIALIZATIONPLUGIN_PLUGIN_H_ #include - #include #include +class InitializationPlugin_EvalListener; + /**\class InitializationPlugin_Plugin * \ingroup Plugins * This class is represents a plugin. @@ -51,6 +52,9 @@ class InitializationPlugin_Plugin : public Events_Listener /// \param theZ - Z of direction point FeaturePtr createAxis(DocumentPtr theDoc, FeaturePtr theOrigin, double theX, double theY, double theZ); + + private: + std::shared_ptr myEvalListener; }; #endif diff --git a/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp b/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp new file mode 100644 index 000000000..ac32047ac --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp @@ -0,0 +1,203 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D +/* + * InitializationPlugin_PyInterp.cpp + * + * Created on: Apr 2, 2015 + * Author: sbh + */ + +#include + +#include +#include + +InitializationPlugin_PyInterp::InitializationPlugin_PyInterp() +: PyInterp_Interp() +{ +} + +InitializationPlugin_PyInterp::~InitializationPlugin_PyInterp() +{ +} + +const char* aSearchCode = + "import ast\n" + "class FindName(ast.NodeVisitor):\n" + " def __init__(self, name):\n" + " self.name = name\n" + " def visit_Name(self, node):\n" + " if node.id == self.name:\n" + " positions.append((node.lineno, node.col_offset))\n" + "FindName(name).visit(ast.parse(expression))"; + +std::list > +InitializationPlugin_PyInterp::positions(const std::string& theExpression, + const std::string& theName) +{ + PyLockWrapper lck; // Acquire GIL until the end of the method + + std::list > aResult; + + // prepare a context + PyObject* aContext = PyDict_New(); + PyObject* aBuiltinModule = PyImport_AddModule("__builtin__"); + PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule); + + // extend aContext with variables + PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str())); + PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str())); + PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]")); + + // run the search code + PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext); + Py_XDECREF(aExecResult); + + // receive results from context + PyObject* aPositions = PyDict_GetItemString(aContext, "positions"); + for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) { + PyObject* aPosition = PyList_GetItem(aPositions, anIndex); + PyObject* aLineNo = PyTuple_GetItem(aPosition, 0); + PyObject* aColOffset = PyTuple_GetItem(aPosition, 1); + + aResult.push_back( + std::pair((int)PyInt_AsLong(aLineNo), + (int)PyInt_AsLong(aColOffset))); + } + + // TODO(spo): after this refCount of the variable is not 0. Is there memory leak? + Py_DECREF(aContext); + + return aResult; +} + + +std::list InitializationPlugin_PyInterp::compile(const std::string& theExpression) +{ + PyLockWrapper lck; // Acquire GIL until the end of the method + 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, (char*)"compile_command", (char*)"(s)", + theExpression.c_str()); + + if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) { + Py_XDECREF(aCodePyObj); + return aResult; + } + + PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj; + std::string aCodeName(PyString_AsString(aCodeObj->co_code)); + // 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; + + size_t params_size = PyTuple_Size(aCodeObj->co_names); + if (params_size > 0) { + for (size_t 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 InitializationPlugin_PyInterp::extendLocalContext(const std::list& theParameters) +{ + PyLockWrapper lck; // Acquire GIL until the end of the method + if (theParameters.empty()) + return; + std::list::const_iterator it = theParameters.begin(); + for ( ; it != theParameters.cend(); it++) { + std::string aParamValue = *it; + simpleRun(aParamValue.c_str(), false); + } +} + +void InitializationPlugin_PyInterp::clearLocalContext() +{ + PyLockWrapper lck; + PyDict_Clear(_local_context); +} + +double InitializationPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError) +{ + PyLockWrapper lck; // Acquire GIL until the end of the method + PyCompilerFlags aFlags = {CO_FUTURE_DIVISION}; + aFlags.cf_flags = CO_FUTURE_DIVISION; + PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(theExpression.c_str(), + "", Py_eval_input, &aFlags); + 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)); + Py_XDECREF(anExprCode); + Py_XDECREF(anEvalResult); + Py_XDECREF(anEvalStrObj); + double result = 0.; + try { + result = std::stod(anEvalStr); + } catch (const std::invalid_argument&) { + theError = "Unable to eval " + anEvalStr; + } + + return result; +} + +std::string InitializationPlugin_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; +} + +bool InitializationPlugin_PyInterp::initContext() +{ + PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context) + if(!m){ + PyErr_Print(); + return false; + } + _global_context = PyModule_GetDict(m); // get interpreter global variable context + Py_INCREF(_global_context); + _local_context = PyDict_New(); + Py_INCREF(_local_context); + + return PyRun_SimpleString("from math import *") == 0; +} + +void InitializationPlugin_PyInterp::closeContext() +{ + Py_XDECREF(_local_context); + PyInterp_Interp::closeContext(); +} diff --git a/src/InitializationPlugin/InitializationPlugin_PyInterp.h b/src/InitializationPlugin/InitializationPlugin_PyInterp.h new file mode 100644 index 000000000..5e4b67163 --- /dev/null +++ b/src/InitializationPlugin/InitializationPlugin_PyInterp.h @@ -0,0 +1,51 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> +/* + * InitializationPlugin_PyInterp.h + * + * Created on: Apr 2, 2015 + * Author: sbh + */ + +#ifndef INITIALIZATIONPLUGIN_PYINTERP_H_ +#define INITIALIZATIONPLUGIN_PYINTERP_H_ + +#include +#include + +#include +#include +#include + +/** + * \class InitializationPlugin_PyInterp + * \ingroup Plugins + * \brief Helper class for using Python interpreter. + */ +class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_PyInterp : public PyInterp_Interp +{ + public: + InitializationPlugin_PyInterp(); + virtual ~InitializationPlugin_PyInterp(); + + /// Returns a list of positions for theName in theExpression. + std::list > positions(const std::string& theExpression, + const std::string& theName); + /// Compiles theExpression and returns a list of parameters used in theExpression. + std::list compile(const std::string& theExpression); + /// Extends local context with the list of parameters. + void extendLocalContext(const std::list& theParameters); + /// Clears local context. + void clearLocalContext(); + /// Evaluates theExpression and returns its value. + double evaluate(const std::string& theExpression, std::string& theError); + + protected: + /// Returns error message. + std::string errorMessage(); + /// Overrides PyInterp_Interp. + virtual bool initContext(); + /// Reimplemented from PyInterp_Interp::closeContext(). + virtual void closeContext(); +}; + +#endif /* INITIALIZATIONPLUGIN_PYINTERP_H_ */ diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index 1cdf80511..9284b18af 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -97,17 +97,13 @@ std::list ModelAPI_FeatureStateMessage::features() const } -ModelAPI_DocumentCreatedMessage::ModelAPI_DocumentCreatedMessage(const Events_ID theID, - const void* theSender) +ModelAPI_DocumentCreatedMessage::ModelAPI_DocumentCreatedMessage( + const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) -{ - -} +{} ModelAPI_DocumentCreatedMessage::~ModelAPI_DocumentCreatedMessage() -{ - -} +{} DocumentPtr ModelAPI_DocumentCreatedMessage::document() const { @@ -119,28 +115,110 @@ void ModelAPI_DocumentCreatedMessage::setDocument(DocumentPtr theDocument) myDocument = theDocument; } -ModelAPI_AttributeEvalMessage::ModelAPI_AttributeEvalMessage(const Events_ID theID, - const void* theSender) +ModelAPI_AttributeEvalMessage::ModelAPI_AttributeEvalMessage( + const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) +{} + +ModelAPI_AttributeEvalMessage::~ModelAPI_AttributeEvalMessage() +{} + +AttributePtr ModelAPI_AttributeEvalMessage::attribute() const +{ + return myAttribute; +} + +void ModelAPI_AttributeEvalMessage::setAttribute(AttributePtr theAttribute) { + myAttribute = theAttribute; +} +ModelAPI_ParameterEvalMessage::ModelAPI_ParameterEvalMessage( + const Events_ID theID, const void* theSender) + : Events_Message(theID, theSender), myIsProcessed(false) +{} + +ModelAPI_ParameterEvalMessage::~ModelAPI_ParameterEvalMessage() +{} + +FeaturePtr ModelAPI_ParameterEvalMessage::parameter() const +{ + return myParam; } -ModelAPI_AttributeEvalMessage::~ModelAPI_AttributeEvalMessage() +void ModelAPI_ParameterEvalMessage::setParameter(FeaturePtr theParam) { + myParam = theParam; +} +void ModelAPI_ParameterEvalMessage::setResults( + const std::list >& theParamsList, + const double theResult, const std::string& theError) +{ + myParamsList = theParamsList; + myResult = theResult; + myError = theError; + myIsProcessed = true; } -AttributePtr ModelAPI_AttributeEvalMessage::attribute() const +bool ModelAPI_ParameterEvalMessage::isProcessed() { - return myAttribute; + return myIsProcessed; } -void ModelAPI_AttributeEvalMessage::setAttribute(AttributePtr theDocument) +const std::list >& + ModelAPI_ParameterEvalMessage::params() const { - myAttribute = theDocument; + return myParamsList; } +const double& ModelAPI_ParameterEvalMessage::result() const +{ + return myResult; +} + +const std::string& ModelAPI_ParameterEvalMessage::error() const +{ + return myError; +} + +ModelAPI_ComputePositionsMessage::ModelAPI_ComputePositionsMessage( + const Events_ID theID, const void* theSender) + : Events_Message(theID, theSender) +{} + +ModelAPI_ComputePositionsMessage::~ModelAPI_ComputePositionsMessage() +{} + +const std::string& ModelAPI_ComputePositionsMessage::expression() const +{ + return myExpression; +} + +const std::string& ModelAPI_ComputePositionsMessage::parameter() const +{ + return myParamName; +} + +void ModelAPI_ComputePositionsMessage::set( + const std::string& theExpression, const std::string& theParameter) +{ + myExpression = theExpression; + myParamName = theParameter; +} + +void ModelAPI_ComputePositionsMessage::setPositions( + const std::list >& thePositions) +{ + myPositions = thePositions; +} + +const std::list >& ModelAPI_ComputePositionsMessage::positions() const +{ + return myPositions; +} + + ModelAPI_ObjectRenamedMessage::ModelAPI_ObjectRenamedMessage(const Events_ID theID, const void* theSender) : Events_Message(theID, theSender) diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index f162734b1..92d200599 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -21,6 +21,7 @@ class ModelAPI_Document; +class ModelAPI_ResultParameter; /// Event ID that feature is created (comes with ModelAPI_ObjectUpdatedMessage) static const char * EVENT_OBJECT_CREATED = "ObjectCreated"; @@ -247,6 +248,109 @@ class ModelAPI_AttributeEvalMessage : public Events_Message MODELAPI_EXPORT void setAttribute(AttributePtr theAttribute); }; +/// Message that parameter feature expression should be evaluated: value and error producing +class ModelAPI_ParameterEvalMessage : public Events_Message +{ + FeaturePtr myParam; ///< parameters that should be evaluated + bool myIsProcessed; ///< true if results were set + /// result of processing, list of parameters in expression found + std::list > myParamsList; + double myResult; ///< result of processing, the computed value of the expression + std::string myError; ///< error of processing, empty if there is no error + + public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char * MY_PARAMETER_EVALUATION_EVENT_ID("ParameterEvaluationRequest"); + static Events_ID anId = Events_Loop::eventByName(MY_PARAMETER_EVALUATION_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the event. + /// Returns the message, processed, with the resulting fields filled. + MODELAPI_EXPORT static std::shared_ptr + send(FeaturePtr theParameter, const void* theSender) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ParameterEvalMessage(eventId(), theSender)); + aMessage->setParameter(theParameter); + Events_Loop::loop()->send(aMessage); + return aMessage; + } + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ParameterEvalMessage(const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ParameterEvalMessage(); + + /// Returns a parameter stored in the message + MODELAPI_EXPORT FeaturePtr parameter() const; + /// Sets a parameter to the message + MODELAPI_EXPORT void setParameter(FeaturePtr theParam); + /// Sets the results of processing + MODELAPI_EXPORT void setResults( + const std::list >& theParamsList, + const double theResult, const std::string& theError); + /// Returns true if the expression is processed + MODELAPI_EXPORT bool isProcessed(); + /// Returns the results of processing: list of parameters found in the expression + MODELAPI_EXPORT const std::list >& params() const; + /// Returns the expression result + MODELAPI_EXPORT const double& result() const; + /// Returns the interpreter error (empty if no error) + MODELAPI_EXPORT const std::string& error() const; +}; + + +/// Message to ask compute the positions of parameters in the expression +class ModelAPI_ComputePositionsMessage : public Events_Message +{ + std::string myExpression; ///< the expression string + std::string myParamName; ///< name of the parameter to be searched + std::list > myPositions; ///< computation result: start-end position indices + +public: + /// Static. Returns EventID of the message. + MODELAPI_EXPORT static Events_ID& eventId() + { + static const char * MY_COMPUTE_POSITIOND_EVENT_ID("ComputePositionsRequest"); + static Events_ID anId = Events_Loop::eventByName(MY_COMPUTE_POSITIOND_EVENT_ID); + return anId; + } + + /// Useful method that creates and sends the AttributeEvalMessage event + /// Returns the message, processed, with the resulting fields filled + MODELAPI_EXPORT static std::shared_ptr + send(const std::string& theExpression, const std::string& theParameter, const void* theSender) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_ComputePositionsMessage(eventId(), theSender)); + aMessage->set(theExpression, theParameter); + Events_Loop::loop()->send(aMessage); + return aMessage; + } + + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_ComputePositionsMessage( + const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_ComputePositionsMessage(); + + /// Returns an expression stored in the message + MODELAPI_EXPORT const std::string& expression() const; + /// Returns a parameter name stored in the message + MODELAPI_EXPORT const std::string& parameter() const; + /// Sets an expression and parameter needed for computation + MODELAPI_EXPORT void set(const std::string& theExpression, const std::string& theParameter); + /// Sets the results of processing + MODELAPI_EXPORT void setPositions(const std::list >& thePositions); + /// Returns the results of processing: position start and end indices + MODELAPI_EXPORT const std::list >& positions() const; +}; + /// Message that the object is renamed class ModelAPI_ObjectRenamedMessage : public Events_Message { diff --git a/src/ParametersPlugin/CMakeLists.txt b/src/ParametersPlugin/CMakeLists.txt index d1cdf512e..d57d1d4ec 100644 --- a/src/ParametersPlugin/CMakeLists.txt +++ b/src/ParametersPlugin/CMakeLists.txt @@ -1,5 +1,4 @@ INCLUDE(Common) -INCLUDE(FindPython) INCLUDE(UnitTest) SET(CMAKE_AUTOMOC ON) @@ -7,9 +6,8 @@ SET(PROJECT_HEADERS ParametersPlugin.h ParametersPlugin_Plugin.h ParametersPlugin_Parameter.h - ParametersPlugin_PyInterp.h + ParametersPlugin_EvalListener.h ParametersPlugin_Validators.h - ParametersPlugin_EvalListener.h ParametersPlugin_WidgetCreator.h ParametersPlugin_ParametersMgr.h ParametersPlugin_WidgetParamsMgr.h @@ -18,9 +16,8 @@ SET(PROJECT_HEADERS SET(PROJECT_SOURCES ParametersPlugin_Plugin.cpp ParametersPlugin_Parameter.cpp - ParametersPlugin_PyInterp.cpp + ParametersPlugin_EvalListener.cpp ParametersPlugin_Validators.cpp - ParametersPlugin_EvalListener.cpp ParametersPlugin_WidgetCreator.cpp ParametersPlugin_ParametersMgr.cpp ParametersPlugin_WidgetParamsMgr.cpp @@ -36,24 +33,18 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events ${PROJECT_SOURCE_DIR}/src/GeomAPI ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/ModuleBase - ${SUIT_INCLUDE} - ${PYTHON_INCLUDE_DIR} ${CAS_INCLUDE_DIRS} ) -MESSAGE(STATUS "PYTHON_LIBRARIES (ParametersPlugin): ${PYTHON_LIBRARIES}") - SET(PROJECT_LIBRARIES Events Config ModelAPI ModuleBase - ${PyInterp} - ${PYTHON_LIBRARIES} ${QT_LIBRARIES} ) -ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS -DHAVE_DEBUG_PYTHON ${CAS_DEFINITIONS}) +ADD_DEFINITIONS(-DPARAMETERSPLUGIN_EXPORTS ${CAS_DEFINITIONS}) SET(TEXT_RESOURCES ParametersPlugin_msg_ru.ts diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp index dbd603f19..f028edefc 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.cpp @@ -10,7 +10,6 @@ #include #include -#include #include @@ -59,16 +58,12 @@ ParametersPlugin_EvalListener::ParametersPlugin_EvalListener() Events_Loop* aLoop = Events_Loop::loop(); Events_ID anEvents_IDs[] = { - ModelAPI_AttributeEvalMessage::eventId(), ModelAPI_ObjectRenamedMessage::eventId(), ModelAPI_ReplaceParameterMessage::eventId() }; for (int i = 0; i < sizeof(anEvents_IDs)/sizeof(anEvents_IDs[0]); ++i) aLoop->registerListener(this, anEvents_IDs[i], NULL, true); - - myInterp = std::shared_ptr(new ParametersPlugin_PyInterp()); - myInterp->initialize(); } ParametersPlugin_EvalListener::~ParametersPlugin_EvalListener() @@ -81,132 +76,13 @@ void ParametersPlugin_EvalListener::processEvent( if (!theMessage.get()) return; - const Events_ID kEvaluationEvent = ModelAPI_AttributeEvalMessage::eventId(); const Events_ID kObjectRenamedEvent = ModelAPI_ObjectRenamedMessage::eventId(); const Events_ID kReplaceParameterEvent = ModelAPI_ReplaceParameterMessage::eventId(); - if (theMessage->eventID() == kEvaluationEvent) { - processEvaluationEvent(theMessage); - } else if (theMessage->eventID() == kObjectRenamedEvent) { + if (theMessage->eventID() == kObjectRenamedEvent) { processObjectRenamedEvent(theMessage); } else if (theMessage->eventID() == kReplaceParameterEvent) { processReplaceParameterEvent(theMessage); - } else { - Events_InfoMessage("ParametersPlugin_EvalListener", - "ParametersPlugin python interpreter, unhandled message caught: ") - .arg(theMessage->eventID().eventText()).send(); - } -} - -double ParametersPlugin_EvalListener::evaluate(FeaturePtr theParameter, - const std::string& theExpression, std::string& theError) -{ - std::list anExprParams = myInterp->compile(theExpression); - // find expression's params in the model - std::list aContext; - std::list::iterator it = anExprParams.begin(); - for ( ; it != anExprParams.end(); it++) { - double aValue; - ResultParameterPtr aParamRes; - // If variable does not exist python interpreter will generate an error. It is OK. - // But due to the issue 1479 it should not check the history position of parameters relatively - // to feature that contains expression - if (!ModelAPI_Tools::findVariable(/*theParameter*/ FeaturePtr(), - *it, aValue, aParamRes, theParameter->document())) - continue; - - aContext.push_back(*it + "=" + toStdString(aValue)); - } - myInterp->extendLocalContext(aContext); - double result = myInterp->evaluate(theExpression, theError); - myInterp->clearLocalContext(); - return result; -} - -void ParametersPlugin_EvalListener::processEvaluationEvent( - const std::shared_ptr& theMessage) -{ - std::shared_ptr aMessage = - std::dynamic_pointer_cast(theMessage); - - FeaturePtr aParamFeature = - std::dynamic_pointer_cast(aMessage->attribute()->owner()); - if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) { - AttributeIntegerPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string anError; - int aValue = (int)evaluate(aParamFeature, anAttribute->text(), anError); - bool isValid = anError.empty(); - if (isValid) - anAttribute->setCalculatedValue(aValue); - anAttribute->setUsedParameters(isValid ? - toSet(myInterp->compile(anAttribute->text())) : std::set()); - anAttribute->setExpressionInvalid(!isValid); - anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); - } else - if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) { - AttributeDoublePtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string anError; - double aValue = evaluate(aParamFeature, anAttribute->text(), anError); - bool isValid = anError.empty(); - if (isValid) - anAttribute->setCalculatedValue(aValue); - anAttribute->setUsedParameters(isValid ? - toSet(myInterp->compile(anAttribute->text())) : std::set()); - anAttribute->setExpressionInvalid(!isValid); - anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError); - } else - if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) { - AttributePointPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string aText[] = { - anAttribute->textX(), - anAttribute->textY(), - anAttribute->textZ() - }; - double aCalculatedValue[] = { - anAttribute->x(), - anAttribute->y(), - anAttribute->z() - }; - for (int i = 0; i < 3; ++i) { - std::string anError; - double aValue = evaluate(aParamFeature, aText[i], anError); - bool isValid = anError.empty(); - if (isValid) aCalculatedValue[i] = aValue; - anAttribute->setUsedParameters(i, - isValid ? toSet(myInterp->compile(aText[i])) : std::set()); - anAttribute->setExpressionInvalid(i, !isValid); - anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); - } - anAttribute->setCalculatedValue(aCalculatedValue[0], - aCalculatedValue[1], - aCalculatedValue[2]); - } else - if (aMessage->attribute()->attributeType() == GeomDataAPI_Point2D::typeId()) { - AttributePoint2DPtr anAttribute = - std::dynamic_pointer_cast(aMessage->attribute()); - std::string aText[] = { - anAttribute->textX(), - anAttribute->textY() - }; - double aCalculatedValue[] = { - anAttribute->x(), - anAttribute->y() - }; - for (int i = 0; i < 2; ++i) { - std::string anError; - double aValue = evaluate(aParamFeature, aText[i], anError); - bool isValid = anError.empty(); - if (isValid) aCalculatedValue[i] = aValue; - anAttribute->setUsedParameters(i, - isValid ? toSet(myInterp->compile(aText[i])) : std::set()); - anAttribute->setExpressionInvalid(i, !isValid); - anAttribute->setExpressionError(i, aText[i].empty() ? "" : anError); - } - anAttribute->setCalculatedValue(aCalculatedValue[0], - aCalculatedValue[1]); } } @@ -217,8 +93,10 @@ std::string ParametersPlugin_EvalListener::renameInPythonExpression( { std::string anExpressionString = theExpression; - std::list > aPositions = - myInterp->positions(anExpressionString, theOldName); + // ask interpreter to compute the positions in the expression + std::shared_ptr aMsg = + ModelAPI_ComputePositionsMessage::send(theExpression, theOldName, this); + const std::list >& aPositions = aMsg->positions(); if (aPositions.empty()) return anExpressionString; diff --git a/src/ParametersPlugin/ParametersPlugin_EvalListener.h b/src/ParametersPlugin/ParametersPlugin_EvalListener.h index 440904783..e16ca0237 100644 --- a/src/ParametersPlugin/ParametersPlugin_EvalListener.h +++ b/src/ParametersPlugin/ParametersPlugin_EvalListener.h @@ -17,7 +17,6 @@ class ModelAPI_Document; class ModelAPI_Feature; class ModelAPI_ResultParameter; class ParametersPlugin_Parameter; -class ParametersPlugin_PyInterp; /** * \class ParametersPlugin_EvalListener @@ -35,12 +34,6 @@ class ParametersPlugin_EvalListener : public Events_Listener virtual void processEvent(const std::shared_ptr& theMessage); protected: - /// Evaluates theExpression and returns its value. - double evaluate(std::shared_ptr theParameter, - const std::string& theExpression, std::string& theError); - - /// Processes Evaluation event. - void processEvaluationEvent(const std::shared_ptr& theMessage); /// Processes ObjectRenamed event. void processObjectRenamedEvent(const std::shared_ptr& theMessage); /// Processes ReplaceParameter event. @@ -62,9 +55,6 @@ class ParametersPlugin_EvalListener : public Events_Listener void renameInDependents(std::shared_ptr theResultParameter, const std::string& theOldName, const std::string& theNewName); - - private: - std::shared_ptr myInterp; }; #endif /* SRC_PARAMETERSPLUGIN_PARAMETERSPLUGIN_EVALLISTENER_H_ */ diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp index 4428be15b..075b5eab4 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.cpp +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.cpp @@ -7,7 +7,6 @@ #include #include "ParametersPlugin_Parameter.h" -#include #include #include @@ -16,14 +15,13 @@ #include #include #include +#include #include #include ParametersPlugin_Parameter::ParametersPlugin_Parameter() { - myInterp = std::shared_ptr(new ParametersPlugin_PyInterp()); - myInterp->initialize(); } ParametersPlugin_Parameter::~ParametersPlugin_Parameter() @@ -97,63 +95,38 @@ void ParametersPlugin_Parameter::execute() double ParametersPlugin_Parameter::evaluate(const std::string& theExpression, std::string& theError) { - std::list anExprParams = myInterp->compile(theExpression); - // find expression's params in the model - std::list aContext; - std::list::iterator it = anExprParams.begin(); - std::list aParamsList; - for ( ; it != anExprParams.end(); it++) { - std::string& aVariableName = *it; - - // Parameter with the same name should be searched in the parent document. - // For the PartSet assume that the parameter is absent. - // Currently there is no way to get parent document, so we get PartSet for all. - DocumentPtr aDocument = document(); - if (data()->name() == aVariableName) { - if (aDocument == ModelAPI_Session::get()->moduleDocument()) - continue; - aDocument = ModelAPI_Session::get()->moduleDocument(); + FeaturePtr aMyPtr = std::dynamic_pointer_cast(data()->owner()); + std::shared_ptr aProcessMessage = + ModelAPI_ParameterEvalMessage::send(aMyPtr, this); + + double aResult = 0; + if (aProcessMessage->isProcessed()) { + const std::list& aParamsList = aProcessMessage->params(); + aResult = aProcessMessage->result(); + theError = aProcessMessage->error(); + // compare the list of parameters to store if changed + AttributeRefListPtr aParams = reflist(ARGUMENTS_ID()); + bool aDifferent = aParams->size() != aParamsList.size(); + if (!aDifferent) { + std::list::const_iterator aNewIter = aParamsList.begin(); + std::list anOldList = aParams->list(); + std::list::const_iterator anOldIter = anOldList.begin(); + for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) { + if (*aNewIter != *anOldIter) + aDifferent = true; + } } - - double aValue; - ResultParameterPtr aParamRes; - if (!ModelAPI_Tools::findVariable(std::dynamic_pointer_cast(data()->owner()), - aVariableName, aValue, aParamRes, aDocument)) continue; - aParamsList.push_back(aParamRes); - - std::ostringstream sstream; - sstream << aValue; - std::string aParamValue = sstream.str(); - size_t aPos = aParamValue.find("."); - std::string aPnt = ""; - if (aPos == std::string::npos) - aPnt = "."; - aContext.push_back(*it + "=" + aParamValue + aPnt); - } - // compare the list of parameters to store if changed - AttributeRefListPtr aParams = reflist(ARGUMENTS_ID()); - bool aDifferent = aParams->size() != aParamsList.size(); - if (!aDifferent) { - std::list::iterator aNewIter = aParamsList.begin(); - std::list anOldList = aParams->list(); - std::list::iterator anOldIter = anOldList.begin(); - for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) { - if (*aNewIter != *anOldIter) - aDifferent = true; + if (aDifferent) { + aParams->clear(); + std::list::const_iterator aNewIter = aParamsList.begin(); + for(; aNewIter != aParamsList.end(); aNewIter++) { + aParams->append(*aNewIter); + } } + } else { // error: python interpreter is not active + theError = "Python interpreter is not available"; } - if (aDifferent) { - aParams->clear(); - std::list::iterator aNewIter = aParamsList.begin(); - for(; aNewIter != aParamsList.end(); aNewIter++) { - aParams->append(*aNewIter); - } - } - - myInterp->extendLocalContext(aContext); - double result = myInterp->evaluate(theExpression, theError); - myInterp->clearLocalContext(); - return result; + return aResult; } bool ParametersPlugin_Parameter::isPreviewNeeded() const diff --git a/src/ParametersPlugin/ParametersPlugin_Parameter.h b/src/ParametersPlugin/ParametersPlugin_Parameter.h index 50be185b2..5f2689c5f 100644 --- a/src/ParametersPlugin/ParametersPlugin_Parameter.h +++ b/src/ParametersPlugin/ParametersPlugin_Parameter.h @@ -12,8 +12,6 @@ #include -class ParametersPlugin_PyInterp; - /** * \class ParametersPlugin_Parameter * \ingroup Plugins @@ -94,9 +92,6 @@ class ParametersPlugin_Parameter : public ModelAPI_Feature void updateName(); /// Updates expression of the parameter bool updateExpression(); - - private: - std::shared_ptr myInterp; }; #endif diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp deleted file mode 100644 index a513b1070..000000000 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -/* - * ParametersPlugin_PyInterp.cpp - * - * Created on: Apr 2, 2015 - * Author: sbh - */ - -#include - -#include -#include - -ParametersPlugin_PyInterp::ParametersPlugin_PyInterp() -: PyInterp_Interp() -{ -} - -ParametersPlugin_PyInterp::~ParametersPlugin_PyInterp() -{ -} - -const char* aSearchCode = - "import ast\n" - "class FindName(ast.NodeVisitor):\n" - " def __init__(self, name):\n" - " self.name = name\n" - " def visit_Name(self, node):\n" - " if node.id == self.name:\n" - " positions.append((node.lineno, node.col_offset))\n" - "FindName(name).visit(ast.parse(expression))"; - -std::list > -ParametersPlugin_PyInterp::positions(const std::string& theExpression, - const std::string& theName) -{ - PyLockWrapper lck; // Acquire GIL until the end of the method - - std::list > aResult; - - // prepare a context - PyObject* aContext = PyDict_New(); - PyObject* aBuiltinModule = PyImport_AddModule("__builtin__"); - PyDict_SetItemString(aContext, "__builtins__", aBuiltinModule); - - // extend aContext with variables - PyDict_SetItemString(aContext, "expression", PyString_FromString(theExpression.c_str())); - PyDict_SetItemString(aContext, "name", PyString_FromString(theName.c_str())); - PyDict_SetItemString(aContext, "positions", Py_BuildValue("[]")); - - // run the search code - PyObject* aExecResult = PyRun_String(aSearchCode, Py_file_input, aContext, aContext); - Py_XDECREF(aExecResult); - - // receive results from context - PyObject* aPositions = PyDict_GetItemString(aContext, "positions"); - for (int anIndex = 0; anIndex < PyList_Size(aPositions); ++anIndex) { - PyObject* aPosition = PyList_GetItem(aPositions, anIndex); - PyObject* aLineNo = PyTuple_GetItem(aPosition, 0); - PyObject* aColOffset = PyTuple_GetItem(aPosition, 1); - - aResult.push_back( - std::pair((int)PyInt_AsLong(aLineNo), - (int)PyInt_AsLong(aColOffset))); - } - - // TODO(spo): after this refCount of the variable is not 0. Is there memory leak? - Py_DECREF(aContext); - - return aResult; -} - - -std::list ParametersPlugin_PyInterp::compile(const std::string& theExpression) -{ - PyLockWrapper lck; // Acquire GIL until the end of the method - 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, (char*)"compile_command", (char*)"(s)", - theExpression.c_str()); - - if(!aCodePyObj || aCodePyObj == Py_None || !PyCode_Check(aCodePyObj)) { - Py_XDECREF(aCodePyObj); - return aResult; - } - - PyCodeObject* aCodeObj = (PyCodeObject*) aCodePyObj; - std::string aCodeName(PyString_AsString(aCodeObj->co_code)); - // 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; - - size_t params_size = PyTuple_Size(aCodeObj->co_names); - if (params_size > 0) { - for (size_t 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) -{ - PyLockWrapper lck; // Acquire GIL until the end of the method - if (theParameters.empty()) - return; - std::list::const_iterator it = theParameters.begin(); - for ( ; it != theParameters.cend(); it++) { - std::string aParamValue = *it; - simpleRun(aParamValue.c_str(), false); - } -} - -void ParametersPlugin_PyInterp::clearLocalContext() -{ - PyLockWrapper lck; - PyDict_Clear(_local_context); -} - -double ParametersPlugin_PyInterp::evaluate(const std::string& theExpression, std::string& theError) -{ - PyLockWrapper lck; // Acquire GIL until the end of the method - PyCompilerFlags aFlags = {CO_FUTURE_DIVISION}; - aFlags.cf_flags = CO_FUTURE_DIVISION; - PyCodeObject* anExprCode = (PyCodeObject *) Py_CompileStringFlags(theExpression.c_str(), - "", Py_eval_input, &aFlags); - 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)); - Py_XDECREF(anExprCode); - Py_XDECREF(anEvalResult); - Py_XDECREF(anEvalStrObj); - double result = 0.; - try { - result = std::stod(anEvalStr); - } catch (const std::invalid_argument&) { - theError = "Unable to eval " + 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; -} - -bool ParametersPlugin_PyInterp::initContext() -{ - PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context) - if(!m){ - PyErr_Print(); - return false; - } - _global_context = PyModule_GetDict(m); // get interpreter global variable context - Py_INCREF(_global_context); - _local_context = PyDict_New(); - Py_INCREF(_local_context); - - return PyRun_SimpleString("from math import *") == 0; -} - -void ParametersPlugin_PyInterp::closeContext() -{ - Py_XDECREF(_local_context); - PyInterp_Interp::closeContext(); -} diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.h b/src/ParametersPlugin/ParametersPlugin_PyInterp.h deleted file mode 100644 index 6f4a30467..000000000 --- a/src/ParametersPlugin/ParametersPlugin_PyInterp.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D --> -/* - * ParametersPlugin_PyInterp.h - * - * Created on: Apr 2, 2015 - * Author: sbh - */ - -#ifndef PARAMETERSPLUGIN_PYINTERP_H_ -#define PARAMETERSPLUGIN_PYINTERP_H_ - -#include -#include - -#include -#include -#include - -/** - * \class ParametersPlugin_PyInterp - * \ingroup Plugins - * \brief Helper class for using Python interpreter. - */ -class PARAMETERSPLUGIN_EXPORT ParametersPlugin_PyInterp : public PyInterp_Interp -{ - public: - ParametersPlugin_PyInterp(); - virtual ~ParametersPlugin_PyInterp(); - - /// Returns a list of positions for theName in theExpression. - std::list > positions(const std::string& theExpression, - const std::string& theName); - /// Compiles theExpression and returns a list of parameters used in theExpression. - std::list compile(const std::string& theExpression); - /// Extends local context with the list of parameters. - void extendLocalContext(const std::list& theParameters); - /// Clears local context. - void clearLocalContext(); - /// Evaluates theExpression and returns its value. - double evaluate(const std::string& theExpression, std::string& theError); - - protected: - /// Returns error message. - std::string errorMessage(); - /// Overrides PyInterp_Interp. - virtual bool initContext(); - /// Reimplemented from PyInterp_Interp::closeContext(). - virtual void closeContext(); -}; - -#endif /* PARAMETERSPLUGIN_PYINTERP_H_ */