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.
Errors.hxx
PyPtr.hxx
Result.hxx
+ py2cpp.hxx
)
ADD_LIBRARY(py2cpp ${_py2cpp_sources})
{
}
+AttributeException::AttributeException(const std::string& message)
+: Exception(message)
+{
+}
+
}
ExecutionException(const std::string& message);
};
+class AttributeException:public Exception
+{
+public:
+ AttributeException(const std::string& message);
+};
+
}
#endif //PY2CPP_ERRORS_HXX
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());
+ }
+}
+
}
#include <Python.h>
#include <tuple>
#include "TypeConversions.hxx"
+#include "Errors.hxx"
+
namespace py2cpp
{
class PyFunction : public PyPtr
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.
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;
}
};
}
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
#include "PyPtr.hxx"
+#include "Errors.hxx"
+
namespace py2cpp
{
{
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;
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;
};
// 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()
{
{
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");
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");
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;
return PyUnicode_FromString(val.c_str());
}
+PyObject * toPy(const char* val)
+{
+ return PyUnicode_FromString(val);
+}
+
ConversionCheck fromPy( PyObject *po, PyObject *& result)
{
result = po;
* 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>
* 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 *&);
--- /dev/null
+
+// 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