Commit 0b7862d6 authored by Joseph Mirabel's avatar Joseph Mirabel Committed by GitHub

Merge pull request #40 from nim65s/devel

fix #39
parents 63d0a6ef 9a27fc49
Pipeline #7538 failed with stage
in 26 minutes and 21 seconds
......@@ -178,12 +178,12 @@ __attribute__((unused)) static struct PyModuleDef dynamicGraphModuleDef = {
NULL,
NULL};
#define GETSTATE(m) ((struct dynamicgraph::python::module_state*)PyModule_GetState(m))
#define DGPYERROR GETSTATE(PyState_FindModule(&dynamicGraphModuleDef))->dgpyError
#define DGPYERROR(m) GETSTATE(m)->dgpyError
#define INITERROR return NULL
#else
__attribute__((unused)) static struct module_state _state;
#define GETSTATE(m) (&dynamicgraph::python::_state)
#define DGPYERROR dynamicgraph::python::_state.dgpyError
#define DGPYERROR(m) dynamicgraph::python::dgpyError
#define INITERROR return
#endif
......
......@@ -7,19 +7,19 @@
/// \brief Catch all exceptions which may be sent when C++ code is
/// called.
#define CATCH_ALL_EXCEPTIONS() \
catch (const std::exception& exc) { \
PyErr_SetString(DGPYERROR, exc.what()); \
return NULL; \
} \
catch (const char* s) { \
PyErr_SetString(DGPYERROR, s); \
return NULL; \
} \
catch (...) { \
PyErr_SetString(DGPYERROR, "Unknown exception"); \
return NULL; \
} \
#define CATCH_ALL_EXCEPTIONS(m) \
catch (const std::exception& exc) { \
PyErr_SetString(DGPYERROR(m), exc.what()); \
return NULL; \
} \
catch (const char* s) { \
PyErr_SetString(DGPYERROR(m), s); \
return NULL; \
} \
catch (...) { \
PyErr_SetString(DGPYERROR(m), "Unknown exception"); \
return NULL; \
} \
struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n
#endif //! DYNAMIC_GRAPH_PYTHON_EXCEPTION
......@@ -21,11 +21,21 @@ typedef boost::shared_ptr<std::ofstream> ofstreamShrPtr;
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
extern PyObject* dgpyError;
# endif
namespace debug {
std::map<std::string, ofstreamShrPtr> mapOfFiles_;
PyObject* addLoggerFileOutputStream(PyObject* /*self*/, PyObject* args) {
PyObject* addLoggerFileOutputStream(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
char* filename;
if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
std::string sfilename(filename);
......@@ -38,49 +48,79 @@ PyObject* addLoggerFileOutputStream(PyObject* /*self*/, PyObject* args) {
dgRTLOG() << "Added " << filename << " as an output stream \n";
mapOfFiles_[sfilename] = ofs_shrptr;
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* closeLoggerFileOutputStream(PyObject* /*self*/, PyObject* /*args */) {
PyObject* closeLoggerFileOutputStream(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
for (std::map<std::string, ofstreamShrPtr>::iterator it = mapOfFiles_.begin(); it != mapOfFiles_.end(); ++it) {
it->second->close();
}
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* addLoggerCoutOutputStream(PyObject* /*self*/, PyObject* /*args*/) {
PyObject* addLoggerCoutOutputStream(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
dgADD_OSTREAM_TO_RTLOG(std::cout);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* realTimeLoggerDestroy(PyObject* /*self*/, PyObject* /*args*/) {
PyObject* realTimeLoggerDestroy(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::destroy();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* realTimeLoggerSpinOnce(PyObject* /*self*/, PyObject* /*args*/) {
PyObject* realTimeLoggerSpinOnce(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::instance().spinOnce();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* realTimeLoggerInstance(PyObject* /*self*/, PyObject* /*args*/) {
PyObject* realTimeLoggerInstance(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::instance();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
......
......@@ -14,10 +14,20 @@
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
PyObject* dgpyError;
# endif
/**
\brief plug a signal into another one.
*/
PyObject* plug(PyObject* /*self*/, PyObject* args) {
PyObject* plug(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
PyObject* objOut = NULL;
PyObject* objIn = NULL;
void* pObjOut;
......@@ -61,11 +71,17 @@ PyObject* plug(PyObject* /*self*/, PyObject* args) {
try {
signalIn->plug(signalOut);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* enableTrace(PyObject* /*self*/, PyObject* args) {
PyObject* enableTrace(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
PyObject* boolean;
char* filename = NULL;
......@@ -82,12 +98,12 @@ PyObject* enableTrace(PyObject* /*self*/, PyObject* args) {
try {
DebugTrace::openFile(filename);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
} else {
try {
DebugTrace::closeFile(filename);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
}
} else {
return NULL;
......@@ -102,8 +118,7 @@ PyObject* error_out(
PyObject*, PyObject*
#endif
) {
struct module_state* st = GETSTATE(m);
PyErr_SetString(st->dgpyError, "something bad happened");
PyErr_SetString(DGPYERROR(m), "something bad happened");
return NULL;
}
......@@ -121,30 +136,29 @@ void initwrap(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject* module = PyModule_Create(&dynamicgraph::python::dynamicGraphModuleDef);
PyObject* m = PyModule_Create(&dynamicgraph::python::dynamicGraphModuleDef);
#else
PyObject* module = Py_InitModule("wrap", dynamicgraph::python::dynamicGraphMethods);
PyObject* m = Py_InitModule("wrap", dynamicgraph::python::dynamicGraphMethods);
#endif
if (module == NULL) INITERROR;
struct dynamicgraph::python::module_state* st = GETSTATE(module);
if (m == NULL) INITERROR;
st->dgpyError = PyErr_NewException(const_cast<char*>("dynamic_graph.dgpyError"), NULL, NULL);
if (st->dgpyError == NULL) {
Py_DECREF(module);
DGPYERROR(m) = PyErr_NewException(const_cast<char*>("dynamic_graph.dgpyError"), NULL, NULL);
if (DGPYERROR(m) == NULL) {
Py_DECREF(m);
INITERROR;
}
Py_XINCREF(st->dgpyError);
if (PyModule_AddObject(module, "dgpyError", st->dgpyError) < 0) {
Py_XDECREF(st->dgpyError);
Py_CLEAR(st->dgpyError);
Py_DECREF(module);
return NULL;
Py_XINCREF(DGPYERROR(m));
if (PyModule_AddObject(m, "dgpyError", DGPYERROR(m)) < 0) {
Py_XDECREF(DGPYERROR(m));
Py_CLEAR(DGPYERROR(m));
Py_DECREF(m);
INITERROR;
}
#if PY_MAJOR_VERSION >= 3
return module;
return m;
#endif
}
......
This diff is collapsed.
......@@ -10,22 +10,38 @@
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
extern PyObject* dgpyError;
# endif
namespace pool {
PyObject* writeGraph(PyObject* /*self*/, PyObject* args) {
PyObject* writeGraph(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
char* filename;
if (!PyArg_ParseTuple(args, "s", &filename)) return NULL;
try {
PoolStorage::getInstance()->writeGraph(filename);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
/**
\brief Get list of entities
*/
PyObject* getEntityList(PyObject* /*self*/, PyObject* args) {
PyObject* getEntityList(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
if (!PyArg_ParseTuple(args, "")) return NULL;
std::vector<std::string> entityNames;
......@@ -47,7 +63,7 @@ PyObject* getEntityList(PyObject* /*self*/, PyObject* args) {
}
return Py_BuildValue("O", classTuple);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return NULL;
}
......
......@@ -21,6 +21,10 @@ using dynamicgraph::SignalBase;
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
extern PyObject* dgpyError;
# endif
using namespace convert;
namespace signalBase {
......@@ -57,20 +61,23 @@ PythonSignalContainer* getPythonSignalContainer() {
const std::string instanceName = "python_signals";
const std::string className = "PythonSignalContainer";
Entity* obj;
#if PY_MAJOR_VERSION >= 3
PyObject* m = PyState_FindModule(&dynamicgraph::python::dynamicGraphModuleDef);
#endif
if (PoolStorage::getInstance()->existEntity(instanceName, obj)) {
if (obj->getClassName() != className) {
std::string msg("Found an object named " + std::string(instanceName) +
",\n"
"but this object is of type " +
std::string(obj->getClassName()) + " and not " + std::string(className));
PyErr_SetString(DGPYERROR, msg.c_str());
PyErr_SetString(DGPYERROR(m), msg.c_str());
return NULL;
}
} else {
try {
obj = FactoryStorage::getInstance()->newEntity(std::string(className), std::string(instanceName));
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
}
return dynamic_cast<PythonSignalContainer*>(obj);
}
......@@ -83,7 +90,13 @@ PythonSignalContainer* getPythonSignalContainer() {
/**
\brief Create an instance of SignalWrapper
*/
PyObject* createSignalWrapper(PyObject* /*self*/, PyObject* args) {
PyObject* createSignalWrapper(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
PythonSignalContainer* psc = getPythonSignalContainer();
if (psc == NULL) return NULL;
......@@ -109,7 +122,7 @@ PyObject* createSignalWrapper(PyObject* /*self*/, PyObject* args) {
}
if (obj == NULL) {
PyErr_SetString(DGPYERROR, error.c_str());
PyErr_SetString(DGPYERROR(m), error.c_str());
return NULL;
}
// Register signal into the python signal container
......@@ -140,13 +153,19 @@ PyObject* getTime(PyObject* /*self*/, PyObject* args) {
return Py_BuildValue("i", time);
}
PyObject* setTime(PyObject* /*self*/, PyObject* args) {
PyObject* setTime(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
int time;
if (!PyArg_ParseTuple(args, "Oi", &object, &time)) return NULL;
if (!PyCapsule_CheckExact(object)) {
PyErr_SetString(DGPYERROR, "object should be a C object");
PyErr_SetString(DGPYERROR(m), "object should be a C object");
return NULL;
}
......@@ -157,7 +176,13 @@ PyObject* setTime(PyObject* /*self*/, PyObject* args) {
return Py_BuildValue("");
}
PyObject* display(PyObject* /*self*/, PyObject* args) {
PyObject* display(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -170,12 +195,18 @@ PyObject* display(PyObject* /*self*/, PyObject* args) {
try {
obj->display(oss);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", oss.str().c_str());
}
PyObject* displayDependencies(PyObject* /*self*/, PyObject* args) {
PyObject* displayDependencies(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
int time;
......@@ -189,11 +220,17 @@ PyObject* displayDependencies(PyObject* /*self*/, PyObject* args) {
try {
obj->displayDependencies(oss, time);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", oss.str().c_str());
}
PyObject* getValue(PyObject* /*self*/, PyObject* args) {
PyObject* getValue(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -274,20 +311,26 @@ PyObject* getValue(PyObject* /*self*/, PyObject* args) {
return Py_BuildValue("d", sigdouble->accessCopy());
}
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
/* Non specific signal: use a generic way. */
std::ostringstream value;
try {
signal->get(value);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
std::string valueString = value.str();
return Py_BuildValue("s", valueString.c_str());
}
PyObject* getName(PyObject* /*self*/, PyObject* args) {
PyObject* getName(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -300,12 +343,18 @@ PyObject* getName(PyObject* /*self*/, PyObject* args) {
try {
name = signal->getName();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", name.c_str());
}
PyObject* getClassName(PyObject* /*self*/, PyObject* args) {
PyObject* getClassName(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -318,12 +367,18 @@ PyObject* getClassName(PyObject* /*self*/, PyObject* args) {
try {
signal->getClassName(name);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", name.c_str());
}
PyObject* setValue(PyObject* /*self*/, PyObject* args) {
PyObject* setValue(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
char* valueString = NULL;
......@@ -340,11 +395,17 @@ PyObject* setValue(PyObject* /*self*/, PyObject* args) {
try {
signal->set(value);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* recompute(PyObject* /*self*/, PyObject* args) {
PyObject* recompute(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
unsigned int time;
......@@ -356,11 +417,17 @@ PyObject* recompute(PyObject* /*self*/, PyObject* args) {
try {
signal->recompute(time);
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* unplug(PyObject* /*self*/, PyObject* args) {
PyObject* unplug(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -371,11 +438,17 @@ PyObject* unplug(PyObject* /*self*/, PyObject* args) {
try {
signal->unplug();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
PyObject* isPlugged(PyObject*, PyObject* args) {
PyObject* isPlugged(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -387,14 +460,20 @@ PyObject* isPlugged(PyObject*, PyObject* args) {
try {
plugged = signal->isPlugged();
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
if (plugged)
return PyBool_FromLong(1);
else
return PyBool_FromLong(0);
}
PyObject* getPlugged(PyObject*, PyObject* args) {
PyObject* getPlugged(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
......@@ -411,7 +490,7 @@ PyObject* getPlugged(PyObject*, PyObject* args) {
throw std::runtime_error(msg);
}
}
CATCH_ALL_EXCEPTIONS();
CATCH_ALL_EXCEPTIONS(m);
// Return the pointer to the signal without destructor since the signal
// is not owned by the calling object.
return PyCapsule_New((void*)otherSignal, "dynamic_graph.Signal", NULL);
......
......@@ -8,11 +8,12 @@
#include <sstream>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/exception-factory.h>
#include "dynamic-graph/factory.h"
#include "dynamic-graph/pool.h"
#include <dynamic-graph/factory.h>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/real-time-logger.h>
#include <dynamic-graph/signal-ptr.h>
#include <dynamic-graph/signal-time-dependent.h>
#include <dynamic-graph/command-bind.h>
namespace dynamicgraph {
class CustomEntity : public Entity {
......@@ -30,6 +31,11 @@ class CustomEntity : public Entity {
{
addSignal();
using namespace dynamicgraph::command;
this->addCommand("act", makeCommandVoid0( *this, &CustomEntity::act,
docCommandVoid0( "act on input signal")));
}
void addSignal() { signalRegistration(m_sigdSIN << m_sigdTimeDepSOUT); }
......@@ -56,6 +62,10 @@ class CustomEntity : public Entity {
sendMsg("end update", MSG_TYPE_ERROR, __FILE__, __LINE__);
return res;
}
void act() {
m_sigdSIN.accessCopy();
}
};
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(CustomEntity, "CustomEntity");
} // namespace dynamicgraph
......@@ -9,11 +9,14 @@ ERR = "dynamic_graph.plug(a, b): Argument '%s' must be of type 'dynamic_graph.Si
class BindingsTests(unittest.TestCase):
def test_bindings(self):
with self.assertRaises(Exception) as cm:
with self.assertRaises(dg.dgpyError) as cm:
dg.error_out()
self.assertEqual(str(cm.exception), "something bad happened")
def test_type_check(self):
"""
test the type checking in signal plugs
"""
first = CustomEntity('first_entity')
second = CustomEntity('second_entity')
# Check that we can connect first.out to second.in
......@@ -29,6 +32,23 @@ class BindingsTests(unittest.TestCase):
dg.plug(first, second.signal('in_double'))
self.assertEqual(str(cm_out.exception), ERR % 'a')
def test_dg_exc(self):
"""
test that exceptions from dynamic graph are correctly raised
"""
ent = CustomEntity('test_dg_exc')
# check that accessing a non initialized signal raises
with self.assertRaises(dg.dgpyError) as cm:
ent.act()
self.assertEqual(
str(cm.exception),
'In SignalPtr: SIN ptr not set. (in signal <CustomEntity(test_dg_exc)::input(double)::in_double>)')
# check that accessing an initialized signal doesn't raise
ent_2 = CustomEntity('another_entity')
dg.plug(ent_2.signal('out_double'), ent.signal('in_double'))
ent.act()
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment