Salome HOME
Various improvements.
authorOvidiu Mircescu <ovidiu.mircescu@edf.fr>
Mon, 4 Feb 2019 16:42:41 +0000 (17:42 +0100)
committerOvidiu Mircescu <ovidiu.mircescu@edf.fr>
Mon, 4 Feb 2019 16:42:41 +0000 (17:42 +0100)
Add convertions for unsigned, bool and char*.
Add setAttr function for convenience.
Use exceptions for the error management of some functions.
Create a global header py2cpp.hxx.

src/CMakeLists.txt
src/Errors.cxx
src/Errors.hxx
src/PyFunction.cxx
src/PyFunction.hxx
src/PyPtr.cxx
src/PyPtr.hxx
src/Test/ConversionTest.cxx
src/TypeConversions.cxx
src/TypeConversions.hxx
src/py2cpp.hxx [new file with mode: 0644]

index 0b05a4cfd405f8107855838943a56f8137b7317d..fbd6d768ba7c1cf923ad8812673cb377bf92e2f4 100644 (file)
@@ -41,6 +41,7 @@ SET(_py2cpp_headers
   Errors.hxx
   PyPtr.hxx
   Result.hxx
+  py2cpp.hxx
 )
 
 ADD_LIBRARY(py2cpp ${_py2cpp_sources})
index d6b0d5976cf4741518d49a533fdaa2af7b362a33..eb80814e69f12500f804c0d20879ac8f9d5bcb3a 100644 (file)
@@ -171,4 +171,9 @@ ExecutionException::ExecutionException(const std::string& message)
 {
 }
 
+AttributeException::AttributeException(const std::string& message)
+: Exception(message)
+{
+}
+
 }
index 56a2a1fff0d5dd90f8a9f71911de1148367d0b2e..bf709c3f3471ec576d39ff253bd5342293f34516 100644 (file)
@@ -73,6 +73,12 @@ public:
   ExecutionException(const std::string& message);
 };
 
+class AttributeException:public Exception
+{
+public:
+  AttributeException(const std::string& message);
+};
+
 }
 
 #endif //PY2CPP_ERRORS_HXX
index f2b1c02e9c01898f48f2dcd9c7d01038cf21fa02..874273456481e71842586bde30d9a80564dfc74e 100644 (file)
@@ -61,4 +61,39 @@ bool PyFunction::load(PyObject* obj, const std::string& function)
   return result;
 }
 
+void PyFunction::loadExp(const std::string& module, const std::string& function)
+{
+  if(!load(module, function))
+  {
+    std::string errorMessage = "Failed to load function '";
+    errorMessage += function;
+    errorMessage += "' from module '";
+    errorMessage += module;
+    errorMessage += "'\n";
+    throw ExecutionException(errorMessage+getLastPyError());
+  }
+}
+
+void PyFunction::loadExp(const PyPtr& obj, const std::string& function)
+{
+  if(!load(obj, function))
+  {
+    std::string errorMessage = "Failed to load function '";
+    errorMessage += function;
+    errorMessage += "' from a python object.\n";
+    throw ExecutionException(errorMessage+getLastPyError());
+  }
+}
+
+void PyFunction::loadExp(PyObject* obj, const std::string& function)
+{
+  if(!load(obj, function))
+  {
+    std::string errorMessage = "Failed to load function '";
+    errorMessage += function;
+    errorMessage += "' from a python object.\n";
+    throw ExecutionException(errorMessage+getLastPyError());
+  }
+}
+
 }
index 2a94118fa292320f5f93b3e85ace794b07a120e3..65cb05265a0d1e24cbdf99cb87efc062091fec1f 100644 (file)
@@ -21,6 +21,8 @@
 #include <Python.h>
 #include <tuple>
 #include "TypeConversions.hxx"
+#include "Errors.hxx"
+
 namespace py2cpp
 {
 class PyFunction : public PyPtr
@@ -32,6 +34,12 @@ public:
   bool load(const PyPtr& obj, const std::string& function);
   bool load(PyObject* obj, const std::string& function);
 
+  // The following versions of the functions throw ExecutionException in case of
+  // failure.
+  void loadExp(const std::string& module, const std::string& function);
+  void loadExp(const PyPtr& obj, const std::string& function);
+  void loadExp(PyObject* obj, const std::string& function);
+
   /*!
    * The evaluation returns nullptr if the python function throws an exception.
    * See PyObject_CallObject documentation.
@@ -40,15 +48,20 @@ public:
   template <class ...Ts>
   PyPtr operator()(const Ts&... args)
   {
-    PyObject * result = nullptr;
+    PyPtr result;
     PyObject * myFunc = get();
     if(myFunc && PyCallable_Check(myFunc))
     {
       std::tuple<const Ts&...> tupleArgs(args...);
       PyPtr pyArgs(toPy(tupleArgs));
-      result = PyObject_CallObject(myFunc, pyArgs.get());
+      result.reset(PyObject_CallObject(myFunc, pyArgs.get()));
+    }
+    if(!result)
+    {
+      std::string errorMessage = "Failed to execute python function.\n";
+      throw ExecutionException(errorMessage+getLastPyError());
     }
-    return PyPtr(result);
+    return result;
   }
 };
 }
index 3741c7818876a5a5498fd4f841775ecb51eed569..c5624bce28d4c486c249e88064dad6ddcea03d6e 100644 (file)
@@ -17,6 +17,8 @@
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 #include "PyPtr.hxx"
+#include "Errors.hxx"
+
 namespace py2cpp
 {
 
@@ -24,12 +26,47 @@ PyPtr PyPtr::getAttr(const std::string& attribute)const
 {
   PyObject* result = nullptr;
   PyObject* thisObj = get();
-  if(thisObj)
-    result = PyObject_GetAttrString(thisObj, attribute.c_str());
-  
+  if(nullptr == thisObj)
+  {
+    std::string message = "Cannot get attribute ";
+    message += attribute;
+    message += " on a NULL object.\n";
+    throw AttributeException(message);
+  }
+
+  if(!PyObject_HasAttrString(thisObj, attribute.c_str()))
+  {
+    std::string message = "Attribute ";
+    message += attribute;
+    message += " does not exist.\n";
+    throw AttributeException(message);
+  }
+
+  result = PyObject_GetAttrString(thisObj, attribute.c_str());
   return PyPtr(result);
 }
 
+void PyPtr::setAttr(const std::string& attribute, const PyPtr& value)const
+{
+  PyObject* thisObj = get();
+  if(nullptr == thisObj)
+  {
+    std::string message = "Cannot set attribute ";
+    message += attribute;
+    message += " on a NULL object.\n";
+    throw AttributeException(message);
+  }
+
+  if(0 > PyObject_SetAttrString(thisObj, attribute.c_str(), value.get()))
+  {
+    std::string message = "Failed to set attribute ";
+    message += attribute;
+    message += ".\n";
+    message += getLastPyError();
+    throw AttributeException(message);
+  }
+}
+
 std::string PyPtr::repr()const
 {
   std::string result;
index fdfd37be9eed951e2a851f2c5b2107a69436596b..9c794f6229cf1d51558bcb8ab2aa37cf5e507c12 100644 (file)
@@ -37,6 +37,7 @@ class PyPtr: public _PyPtr
 public:
   using _PyPtr::_PyPtr;
   PyPtr getAttr(const std::string& attribute)const;
+  void setAttr(const std::string& attribute, const PyPtr& value)const;
   std::string repr()const;
 };
 
index ed93db568ff6d71ca4d7bb4b68015f26c3833939..e4e704b657e509b3377dc8a35768263fa37f7637 100644 (file)
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 #include "ConversionTest.hxx"
-
-#include "TypeConversions.hxx"
-#include "Result.hxx"
-#include "PyFunction.hxx"
+#include "py2cpp.hxx"
 
 void ConversionTest::setUp()
 {
@@ -38,6 +35,8 @@ void ConversionTest::basicTest()
 {
   CPPUNIT_ASSERT(42==py2cpp::fromPyPtr<int>(py2cpp::toPyPtr(42)));
   CPPUNIT_ASSERT(4.2==py2cpp::fromPyPtr<double>(py2cpp::toPyPtr(4.2)));
+  CPPUNIT_ASSERT(py2cpp::fromPyPtr<bool>(py2cpp::toPyPtr(true)));
+  CPPUNIT_ASSERT(!py2cpp::fromPyPtr<bool>(py2cpp::toPyPtr(false)));
   std::string toto;
   toto = py2cpp::fromPyPtr<std::string>(py2cpp::toPyPtr(std::string("toto")));
   CPPUNIT_ASSERT(toto == "toto");
@@ -165,6 +164,17 @@ void ConversionTest::pyErrorTest()
   std::string str;
   py2cpp::PyFunction fn;
   fn.load("TestPy2cpp", "f3");
+  try
+  {
+    fn(7, 0, "problem");
+    CPPUNIT_FAIL("Expected exception 'py2cpp::ExecutionException'!");
+  }
+  catch (const py2cpp::ExecutionException& err)
+  {
+    str = err.what();
+    CPPUNIT_ASSERT(str.find("ZeroDivisionError:") != std::string::npos) ;
+  }
+
   try
   {
     py2cpp::pyResult(d, str) = fn(7, 0, "problem");
index 6d674c939801e8af76f0b1db2457bc3c067a2f20..d50b3a84741ea888644c0c830ed738ebabf545eb 100644 (file)
@@ -35,6 +35,36 @@ PyObject * toPy(int val)
   return PyLong_FromLong(val);
 }
 
+ConversionCheck fromPy(PyObject * po, unsigned int& result)
+{
+  ConversionCheck check;
+  if(po && PyLong_Check(po))
+    result = PyLong_AsUnsignedLong(po);
+  else
+    check.addError("int", po);
+  return check;
+}
+
+PyObject * toPy(unsigned int val)
+{
+  return PyLong_FromUnsignedLong(val);
+}
+
+ConversionCheck fromPy(PyObject * po, bool& result)
+{
+  ConversionCheck check;
+  if(po && PyBool_Check(po))
+    result = (Py_True == po);
+  else
+    check.addError("bool", po);
+  return check;
+}
+
+PyObject * toPy(bool val)
+{
+  return PyBool_FromLong(val);
+}
+
 ConversionCheck fromPy(PyObject * po, double& result)
 {
   ConversionCheck check;
@@ -70,6 +100,11 @@ PyObject * toPy(const std::string& val)
   return PyUnicode_FromString(val.c_str());
 }
 
+PyObject * toPy(const char* val)
+{
+  return PyUnicode_FromString(val);
+}
+
 ConversionCheck fromPy( PyObject *po, PyObject *& result)
 {
   result = po;
index e035b2edcd9f8c9cffa0934abcfcb3e3305105c5..9e04d57959612a95c44d8e25ff04b09123ad868b 100644 (file)
@@ -35,8 +35,11 @@ namespace py2cpp
  * The conversion is always possible and it does not throw exceptions.
  */
 PyObject * toPy(int);
+PyObject * toPy(unsigned int);
+PyObject * toPy(bool);
 PyObject * toPy(double);
 PyObject * toPy(const std::string&);
+PyObject * toPy(const char*);
 PyObject * toPy(PyObject *);
 PyObject * toPy(const PyPtr&);
 template <class T>
@@ -54,6 +57,8 @@ PyObject * toPy(const std::tuple<Ts...>& vars );
  * error message. No exception is thrown.
  */
 ConversionCheck fromPy( PyObject *, int&);
+ConversionCheck fromPy( PyObject *, unsigned int&);
+ConversionCheck fromPy( PyObject *, bool&);
 ConversionCheck fromPy( PyObject *, double&);
 ConversionCheck fromPy( PyObject *, std::string&);
 ConversionCheck fromPy( PyObject *, PyObject *&);
diff --git a/src/py2cpp.hxx b/src/py2cpp.hxx
new file mode 100644 (file)
index 0000000..4eb7e4f
--- /dev/null
@@ -0,0 +1,26 @@
+
+// Copyright (C) 2019  EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#ifndef PY2CPP_PY2CPP_HXX
+#define PY2CPP_PY2CPP_HXX
+
+#include "PyFunction.hxx"
+#include "Result.hxx"
+
+#endif //PY2CPP_PY2CPP_HXX