]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #1806 : evaluation of expressions if no parameters defined.
authormpv <mpv@opencascade.com>
Wed, 23 Nov 2016 09:39:26 +0000 (12:39 +0300)
committermpv <mpv@opencascade.com>
Wed, 23 Nov 2016 09:39:26 +0000 (12:39 +0300)
Now the python interpreter is loaded in Initialization plugin and accessible for any expression evaluation even if no parameters were created.

16 files changed:
src/InitializationPlugin/CMakeLists.txt
src/InitializationPlugin/InitializationPlugin_EvalListener.cpp [new file with mode: 0644]
src/InitializationPlugin/InitializationPlugin_EvalListener.h [new file with mode: 0644]
src/InitializationPlugin/InitializationPlugin_Plugin.cpp
src/InitializationPlugin/InitializationPlugin_Plugin.h
src/InitializationPlugin/InitializationPlugin_PyInterp.cpp [new file with mode: 0644]
src/InitializationPlugin/InitializationPlugin_PyInterp.h [new file with mode: 0644]
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ParametersPlugin/CMakeLists.txt
src/ParametersPlugin/ParametersPlugin_EvalListener.cpp
src/ParametersPlugin/ParametersPlugin_EvalListener.h
src/ParametersPlugin/ParametersPlugin_Parameter.cpp
src/ParametersPlugin/ParametersPlugin_Parameter.h
src/ParametersPlugin/ParametersPlugin_PyInterp.cpp [deleted file]
src/ParametersPlugin/ParametersPlugin_PyInterp.h [deleted file]

index 7967fcc67de882c144aab927d4e171bf432f7a46..e5b0ce86b582d7377b151870140cd46eddbb4ee8 100644 (file)
@@ -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 (file)
index 0000000..86d457a
--- /dev/null
@@ -0,0 +1,210 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+/*
+ * InitializationPlugin_EvalListener.cpp
+ *
+ *  Created on: Apr 28, 2015
+ *      Author: sbh
+ */
+
+#include <pyconfig.h>
+
+#include <InitializationPlugin_EvalListener.h>
+#include <ParametersPlugin_Parameter.h>
+#include <InitializationPlugin_PyInterp.h>
+
+#include <Events_InfoMessage.h>
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeValidator.h>
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+
+#include <string>
+#include <set>
+#include <sstream>
+
+//------------------------------------------------------------------------------
+// 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<std::string> toSet(const std::list<std::string>& theContainer)
+{
+  return std::set<std::string>(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<InitializationPlugin_PyInterp>(new InitializationPlugin_PyInterp());
+  myInterp->initialize();
+}
+
+InitializationPlugin_EvalListener::~InitializationPlugin_EvalListener()
+{
+}
+
+void InitializationPlugin_EvalListener::processEvent(
+    const std::shared_ptr<Events_Message>& theMessage)
+{
+  if (!theMessage.get())
+    return;
+
+  if (theMessage->eventID() == ModelAPI_AttributeEvalMessage::eventId()) {
+    processEvaluationEvent(theMessage);
+  } else if (theMessage->eventID() == ModelAPI_ParameterEvalMessage::eventId()) {
+    std::shared_ptr<ModelAPI_ParameterEvalMessage> aMsg =
+      std::dynamic_pointer_cast<ModelAPI_ParameterEvalMessage>(theMessage);
+    FeaturePtr aParam = aMsg->parameter();
+    std::string anExp = aParam->string(ParametersPlugin_Parameter::EXPRESSION_ID())->value();
+    std::string anError;
+    std::list<std::shared_ptr<ModelAPI_ResultParameter> > aParamsList;
+    double aResult = evaluate(aParam, anExp, anError, aParamsList, true);
+    aMsg->setResults(aParamsList, aResult, anError);
+  } else if (theMessage->eventID() == ModelAPI_ComputePositionsMessage::eventId()) {
+    std::shared_ptr<ModelAPI_ComputePositionsMessage> aMsg =
+      std::dynamic_pointer_cast<ModelAPI_ComputePositionsMessage>(theMessage);
+    aMsg->setPositions(myInterp->positions(aMsg->expression(), aMsg->parameter()));
+  }
+}
+
+double InitializationPlugin_EvalListener::evaluate(FeaturePtr theParameter,
+  const std::string& theExpression, std::string& theError,
+  std::list<std::shared_ptr<ModelAPI_ResultParameter> >& theParamsList,
+  const bool theIsParameter)
+{
+  std::list<std::string> anExprParams = myInterp->compile(theExpression);
+  // find expression's params in the model
+  std::list<std::string> aContext;
+  std::list<std::string>::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<Events_Message>& theMessage)
+{
+  std::shared_ptr<ModelAPI_AttributeEvalMessage> aMessage =
+      std::dynamic_pointer_cast<ModelAPI_AttributeEvalMessage>(theMessage);
+
+  std::list<std::shared_ptr<ModelAPI_ResultParameter> > aParamsList;
+  FeaturePtr aParamFeature =
+    std::dynamic_pointer_cast<ModelAPI_Feature>(aMessage->attribute()->owner());
+  if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) {
+    AttributeIntegerPtr anAttribute =
+        std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(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<std::string>());
+    anAttribute->setExpressionInvalid(!isValid);
+    anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError);
+  } else
+  if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) {
+    AttributeDoublePtr anAttribute =
+        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(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<std::string>());
+    anAttribute->setExpressionInvalid(!isValid);
+    anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError);
+  } else
+  if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) {
+    AttributePointPtr anAttribute =
+        std::dynamic_pointer_cast<GeomDataAPI_Point>(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<std::string>());
+      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<GeomDataAPI_Point2D>(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<std::string>());
+      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 (file)
index 0000000..9ddb19d
--- /dev/null
@@ -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 <InitializationPlugin.h>
+#include <Events_Loop.h>
+
+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<Events_Message>& theMessage);
+
+ protected:
+  /// Evaluates theExpression and returns its value.
+   double evaluate(std::shared_ptr<ModelAPI_Feature> theParameter,
+                  const std::string& theExpression, std::string& theError,
+                  std::list<std::shared_ptr<ModelAPI_ResultParameter> >& theParamsList,
+                  const bool theIsParameter = false);
+
+  /// Processes Evaluation event.
+  void processEvaluationEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+ private:
+  std::shared_ptr<InitializationPlugin_PyInterp> myInterp;
+};
+
+#endif /* SRC_INITIALIZATIONPLUGIN_INITIALIZATIONPLUGIN_EVALLISTENER_H_ */
index ee76b04d279dac93553611358e09753611dc9bcb..5367ef276c7899cf7786b4fd574e7c7ab55a34e8 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <InitializationPlugin_Plugin.h>
 
+#include <InitializationPlugin_EvalListener.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Document.h>
 #include <ModelAPI_AttributeBoolean.h>
@@ -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<InitializationPlugin_EvalListener>(new InitializationPlugin_EvalListener());
 }
 
 void InitializationPlugin_Plugin::processEvent(const std::shared_ptr<Events_Message>& theMessage)
index 6f06f059fed721e2843871f487319ec1eff83d21..52d5cc3e93664e2460c9c506175323fe31e60e65 100644 (file)
@@ -4,11 +4,12 @@
 #define INITIALIZATIONPLUGIN_PLUGIN_H_
 
 #include <InitializationPlugin.h>
-
 #include <ModelAPI_Feature.h>
 
 #include <Events_Loop.h>
 
+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<InitializationPlugin_EvalListener> myEvalListener;
 };
 
 #endif
diff --git a/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp b/src/InitializationPlugin/InitializationPlugin_PyInterp.cpp
new file mode 100644 (file)
index 0000000..ac32047
--- /dev/null
@@ -0,0 +1,203 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+/*
+ * InitializationPlugin_PyInterp.cpp
+ *
+ *  Created on: Apr 2, 2015
+ *      Author: sbh
+ */
+
+#include <InitializationPlugin_PyInterp.h>
+
+#include <string>
+#include <stdexcept>
+
+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<std::pair<int, int> >
+InitializationPlugin_PyInterp::positions(const std::string& theExpression,
+                                     const std::string& theName)
+{
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+
+  std::list<std::pair<int, int> > 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, int>((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<std::string> InitializationPlugin_PyInterp::compile(const std::string& theExpression)
+{
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+  std::list<std::string> 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<std::string>& theParameters)
+{
+  PyLockWrapper lck; // Acquire GIL until the end of the method
+  if (theParameters.empty())
+    return;
+  std::list<std::string>::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(),
+                                "<string>", 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 (file)
index 0000000..5e4b671
--- /dev/null
@@ -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 <PyInterp_Interp.h>
+#include <InitializationPlugin.h>
+
+#include <list>
+#include <string>
+#include <utility>
+
+/**
+ * \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<std::pair<int, int> > positions(const std::string& theExpression,
+                                            const std::string& theName);
+  /// Compiles theExpression and returns a list of parameters used in theExpression.
+  std::list<std::string> compile(const std::string& theExpression);
+  /// Extends local context with the list of parameters.
+  void extendLocalContext(const std::list<std::string>& 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_ */
index 1cdf805119d98c69b1947f42312506f26a6a1ca2..9284b18af686d2fd0833ee1dffd5d7402cf7b5b9 100644 (file)
@@ -97,17 +97,13 @@ std::list<std::string> 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<std::shared_ptr<ModelAPI_ResultParameter> >& 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<std::shared_ptr<ModelAPI_ResultParameter> >& 
+  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<std::pair<int, int> >& thePositions)
+{
+  myPositions = thePositions;
+}
+
+const std::list<std::pair<int, int> >& ModelAPI_ComputePositionsMessage::positions() const
+{
+  return myPositions;
+}
+
+
 ModelAPI_ObjectRenamedMessage::ModelAPI_ObjectRenamedMessage(const Events_ID theID,
                                                              const void* theSender)
 : Events_Message(theID, theSender)
index f162734b18a14c2cf3338af525b20ba430cb9bf2..92d20059956d31854c35df24c2eb6a7273cd75d3 100644 (file)
@@ -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<std::shared_ptr<ModelAPI_ResultParameter> > 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<ModelAPI_ParameterEvalMessage>
+    send(FeaturePtr theParameter, const void* theSender)
+  {
+    std::shared_ptr<ModelAPI_ParameterEvalMessage> aMessage =
+      std::shared_ptr<ModelAPI_ParameterEvalMessage>(
+      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<std::shared_ptr<ModelAPI_ResultParameter> >& 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<std::shared_ptr<ModelAPI_ResultParameter> >& 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<std::pair<int, int> > 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<ModelAPI_ComputePositionsMessage>
+    send(const std::string& theExpression, const std::string& theParameter, const void* theSender)
+  {
+    std::shared_ptr<ModelAPI_ComputePositionsMessage> aMessage =
+      std::shared_ptr<ModelAPI_ComputePositionsMessage>(
+      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<std::pair<int, int> >& thePositions);
+  /// Returns the results of processing: position start and end indices
+  MODELAPI_EXPORT const std::list<std::pair<int, int> >& positions() const;
+};
+
 /// Message that the object is renamed
 class ModelAPI_ObjectRenamedMessage : public Events_Message
 {
index d1cdf512e3e93adfe274ca3bb6cbccddbc261a75..d57d1d4ecd3b7ee0e3211ba79179d08d33fe917a 100644 (file)
@@ -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
index dbd603f195a7de1062b563cb50f3abb253e547d5..f028edefc8da58e71a7a40f8b35a1ab4aa33d497 100644 (file)
@@ -10,7 +10,6 @@
 
 #include <ParametersPlugin_EvalListener.h>
 #include <ParametersPlugin_Parameter.h>
-#include <ParametersPlugin_PyInterp.h>
 
 #include <Events_InfoMessage.h>
 
@@ -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<ParametersPlugin_PyInterp>(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<std::string> anExprParams = myInterp->compile(theExpression);
-  // find expression's params in the model
-  std::list<std::string> aContext;
-  std::list<std::string>::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<Events_Message>& theMessage)
-{
-  std::shared_ptr<ModelAPI_AttributeEvalMessage> aMessage =
-      std::dynamic_pointer_cast<ModelAPI_AttributeEvalMessage>(theMessage);
-
-  FeaturePtr aParamFeature =
-    std::dynamic_pointer_cast<ModelAPI_Feature>(aMessage->attribute()->owner());
-  if (aMessage->attribute()->attributeType() == ModelAPI_AttributeInteger::typeId()) {
-    AttributeIntegerPtr anAttribute =
-        std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(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<std::string>());
-    anAttribute->setExpressionInvalid(!isValid);
-    anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError);
-  } else
-  if (aMessage->attribute()->attributeType() == ModelAPI_AttributeDouble::typeId()) {
-    AttributeDoublePtr anAttribute =
-        std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(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<std::string>());
-    anAttribute->setExpressionInvalid(!isValid);
-    anAttribute->setExpressionError(anAttribute->text().empty() ? "" : anError);
-  } else
-  if (aMessage->attribute()->attributeType() == GeomDataAPI_Point::typeId()) {
-    AttributePointPtr anAttribute =
-        std::dynamic_pointer_cast<GeomDataAPI_Point>(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<std::string>());
-      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<GeomDataAPI_Point2D>(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<std::string>());
-      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<std::pair<int, int> > aPositions =
-      myInterp->positions(anExpressionString, theOldName);
+  // ask interpreter to compute the positions in the expression
+  std::shared_ptr<ModelAPI_ComputePositionsMessage> aMsg = 
+    ModelAPI_ComputePositionsMessage::send(theExpression, theOldName, this);
+  const std::list<std::pair<int, int> >& aPositions = aMsg->positions();
 
   if (aPositions.empty())
     return anExpressionString;
index 440904783ce857809d48e600352c7d099055e3df..e16ca02370b51fa76db6532721707391fe136a22 100644 (file)
@@ -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<Events_Message>& theMessage);
 
  protected:
-  /// Evaluates theExpression and returns its value.
-   double evaluate(std::shared_ptr<ModelAPI_Feature> theParameter,
-                  const std::string& theExpression, std::string& theError);
-
-  /// Processes Evaluation event.
-  void processEvaluationEvent(const std::shared_ptr<Events_Message>& theMessage);
   /// Processes ObjectRenamed event.
   void processObjectRenamedEvent(const std::shared_ptr<Events_Message>& theMessage);
   /// Processes ReplaceParameter event.
@@ -62,9 +55,6 @@ class ParametersPlugin_EvalListener : public Events_Listener
   void renameInDependents(std::shared_ptr<ModelAPI_ResultParameter> theResultParameter,
                           const std::string& theOldName,
                           const std::string& theNewName);
-
- private:
-  std::shared_ptr<ParametersPlugin_PyInterp> myInterp;
 };
 
 #endif /* SRC_PARAMETERSPLUGIN_PARAMETERSPLUGIN_EVALLISTENER_H_ */
index 4428be15b7f949ef5dcd3d17adfadf7fc2173b89..075b5eab4f04a60c79cd0b3653fd7d5d41ed195e 100644 (file)
@@ -7,7 +7,6 @@
 #include <pyconfig.h>
 
 #include "ParametersPlugin_Parameter.h"
-#include <ParametersPlugin_PyInterp.h>
 
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_ResultParameter.h>
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Validator.h>
+#include <ModelAPI_Events.h>
 
 #include <string>
 #include <sstream>
 
 ParametersPlugin_Parameter::ParametersPlugin_Parameter()
 {
-  myInterp = std::shared_ptr<ParametersPlugin_PyInterp>(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<std::string> anExprParams = myInterp->compile(theExpression);
-  // find expression's params in the model
-  std::list<std::string> aContext;
-  std::list<std::string>::iterator it = anExprParams.begin();
-  std::list<ResultParameterPtr> 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<ModelAPI_Feature>(data()->owner());
+  std::shared_ptr<ModelAPI_ParameterEvalMessage> aProcessMessage =
+    ModelAPI_ParameterEvalMessage::send(aMyPtr, this);
+
+  double aResult = 0;
+  if (aProcessMessage->isProcessed()) {
+    const std::list<ResultParameterPtr>& 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<ResultParameterPtr>::const_iterator aNewIter = aParamsList.begin();
+      std::list<ObjectPtr> anOldList = aParams->list();
+      std::list<ObjectPtr>::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<ModelAPI_Feature>(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<ResultParameterPtr>::iterator aNewIter = aParamsList.begin();
-    std::list<ObjectPtr> anOldList = aParams->list();
-    std::list<ObjectPtr>::iterator anOldIter = anOldList.begin();
-    for(; !aDifferent && aNewIter != aParamsList.end(); aNewIter++, anOldIter++) {
-      if (*aNewIter != *anOldIter)
-        aDifferent = true;
+    if (aDifferent) {
+      aParams->clear();
+      std::list<ResultParameterPtr>::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<ResultParameterPtr>::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
index 50be185b2fa2796f826e3776b12a4a6afb91f092..5f2689c5fb55c868e38883bdc1dcba3c01e184b6 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <memory>
 
-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<ParametersPlugin_PyInterp> myInterp;
 };
 
 #endif
diff --git a/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp b/src/ParametersPlugin/ParametersPlugin_PyInterp.cpp
deleted file mode 100644 (file)
index a513b10..0000000
+++ /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 <ParametersPlugin_PyInterp.h>
-
-#include <string>
-#include <stdexcept>
-
-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<std::pair<int, int> >
-ParametersPlugin_PyInterp::positions(const std::string& theExpression,
-                                     const std::string& theName)
-{
-  PyLockWrapper lck; // Acquire GIL until the end of the method
-
-  std::list<std::pair<int, int> > 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, int>((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<std::string> ParametersPlugin_PyInterp::compile(const std::string& theExpression)
-{
-  PyLockWrapper lck; // Acquire GIL until the end of the method
-  std::list<std::string> 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<std::string>& theParameters)
-{
-  PyLockWrapper lck; // Acquire GIL until the end of the method
-  if (theParameters.empty())
-    return;
-  std::list<std::string>::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(),
-                                "<string>", 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 (file)
index 6f4a304..0000000
+++ /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 <PyInterp_Interp.h>
-#include <ParametersPlugin.h>
-
-#include <list>
-#include <string>
-#include <utility>
-
-/**
- * \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<std::pair<int, int> > positions(const std::string& theExpression,
-                                            const std::string& theName);
-  /// Compiles theExpression and returns a list of parameters used in theExpression.
-  std::list<std::string> compile(const std::string& theExpression);
-  /// Extends local context with the list of parameters.
-  void extendLocalContext(const std::list<std::string>& 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_ */