entity-py.cc 16.2 KB
Newer Older
Thomas Moulard's avatar
Thomas Moulard committed
1
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
2 3 4 5 6

#include <Python.h>
#include <iostream>

#include <dynamic-graph/entity.h>
florent's avatar
florent committed
7
#include <dynamic-graph/factory.h>
8

9 10 11
#include <dynamic-graph/command.h>
#include <dynamic-graph/value.h>
#include <dynamic-graph/pool.h>
12
#include <dynamic-graph/linear-algebra.h>
florent's avatar
florent committed
13

Guilhem Saurel's avatar
Guilhem Saurel committed
14
#include "dynamic-graph-py.hh"
15 16 17
#include "convert-dg-to-py.hh"
#include "exception.hh"

18 19 20
// Ignore "dereferencing type-punned pointer will break strict-aliasing rules"
// warnings on gcc caused by Py_RETURN_TRUE and Py_RETURN_FALSE.
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
21
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
22 23
#endif

24
using dynamicgraph::Entity;
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
25
using dynamicgraph::Matrix;
26
using dynamicgraph::SignalBase;
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
27
using dynamicgraph::Vector;
florent's avatar
florent committed
28 29
using dynamicgraph::command::Command;
using dynamicgraph::command::Value;
30 31

namespace dynamicgraph {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
namespace python {

using namespace convert;

namespace entity {

/**
   \brief Create an instance of Entity
*/
PyObject* create(PyObject* /*self*/, PyObject* args) {
  char* className = NULL;
  char* instanceName = NULL;

  if (!PyArg_ParseTuple(args, "ss", &className, &instanceName)) return NULL;

  Entity* obj = NULL;
  /* Try to find if the corresponding object already exists. */
  if (dynamicgraph::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));
Guilhem Saurel's avatar
Guilhem Saurel committed
55
      PyErr_SetString(DGPYERROR, msg.c_str());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
56 57 58 59 60 61 62 63 64 65
      return NULL;
    }
  } else /* If not, create a new object. */
  {
    try {
      obj = dynamicgraph::FactoryStorage::getInstance()->newEntity(std::string(className), std::string(instanceName));
    }
    CATCH_ALL_EXCEPTIONS();
  }

66 67
  // Return the pointer as a PyCapsule
  return PyCapsule_New((void*)obj, "dynamic_graph.Entity", NULL);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
68 69 70 71 72 73 74 75 76 77 78
}

/**
   \brief Get name of entity
*/
PyObject* getName(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  void* pointer = NULL;
  std::string name;

  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
79 80
  if (!PyCapsule_CheckExact(object)) {
    PyErr_SetString(PyExc_TypeError, "function takes a PyCapsule as argument");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
81 82 83
    return NULL;
  }

84
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
  Entity* entity = (Entity*)pointer;

  try {
    name = entity->getName();
  }
  CATCH_ALL_EXCEPTIONS();
  return Py_BuildValue("s", name.c_str());
}

/**
   \brief Get class name of entity
*/
PyObject* getClassName(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  void* pointer = NULL;
  std::string name;

  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
103 104
  if (!PyCapsule_CheckExact(object)) {
    PyErr_SetString(PyExc_TypeError, "function takes a PyCapsule as argument");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
105 106 107
    return NULL;
  }

108
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
  Entity* entity = (Entity*)pointer;

  try {
    name = entity->getClassName();
  }
  CATCH_ALL_EXCEPTIONS();
  return Py_BuildValue("s", name.c_str());
}

/**
   \brief Check if the entity has a signal with the given name
*/
PyObject* hasSignal(PyObject* /*self*/, PyObject* args) {
  char* name = NULL;
  PyObject* object = NULL;
  void* pointer = NULL;

  if (!PyArg_ParseTuple(args, "Os", &object, &name)) Py_RETURN_FALSE;

128 129
  if (!PyCapsule_CheckExact(object)) {
    PyErr_SetString(PyExc_TypeError, "function takes a PyCapsule as argument");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
130 131 132
    Py_RETURN_FALSE;
  }

133
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
  Entity* entity = (Entity*)pointer;

  bool hasSignal = false;
  try {
    hasSignal = entity->hasSignal(std::string(name));
  }
  CATCH_ALL_EXCEPTIONS();

  if (hasSignal)
    Py_RETURN_TRUE;
  else
    Py_RETURN_FALSE;
}

/**
   \brief Get a signal by name
*/
PyObject* getSignal(PyObject* /*self*/, PyObject* args) {
  char* name = NULL;
  PyObject* object = NULL;
  void* pointer = NULL;

  if (!PyArg_ParseTuple(args, "Os", &object, &name)) return NULL;

158 159
  if (!PyCapsule_CheckExact(object)) {
    PyErr_SetString(PyExc_TypeError, "function takes a PyCapsule as argument");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
160 161 162
    return NULL;
  }

163
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
164 165 166 167 168 169 170 171 172 173
  Entity* entity = (Entity*)pointer;

  SignalBase<int>* signal = NULL;
  try {
    signal = &(entity->getSignal(std::string(name)));
  }
  CATCH_ALL_EXCEPTIONS();

  // Return the pointer to the signal without destructor since the signal
  // is not owned by the calling object but by the Entity.
174
  return PyCapsule_New((void*)signal, "dynamic_graph.Signal", NULL);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
175 176 177 178 179 180 181 182
}

PyObject* listSignals(PyObject* /*self*/, PyObject* args) {
  void* pointer = NULL;
  PyObject* object = NULL;

  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;

183
  if (!PyCapsule_CheckExact(object)) return NULL;
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
184

185
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
186 187 188 189 190 191 192 193 194 195
  Entity* entity = (Entity*)pointer;

  try {
    Entity::SignalMap signalMap = entity->getSignalMap();
    // Create a tuple of same size as the command map
    PyObject* result = PyTuple_New(signalMap.size());
    unsigned int count = 0;

    for (Entity::SignalMap::iterator it = signalMap.begin(); it != signalMap.end(); it++) {
      SignalBase<int>* signal = it->second;
196
      PyObject* pySignal = PyCapsule_New((void*)signal, "dynamic_graph.Signal", NULL);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
      PyTuple_SET_ITEM(result, count, pySignal);
      count++;
    }
    return result;
  }
  CATCH_ALL_EXCEPTIONS();
  return NULL;
}

PyObject* executeCommand(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  PyObject* argTuple = NULL;
  char* commandName = NULL;
  void* pointer = NULL;
  if (!PyArg_ParseTuple(args, "OsO", &object, &commandName, &argTuple)) {
    return NULL;
  }
  // Retrieve the entity instance
215
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
216 217 218
    PyErr_SetString(PyExc_TypeError, "first argument is not an object");
    return NULL;
  }
219
  pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  Entity* entity = (Entity*)pointer;
  // Retrieve the argument tuple
  if (!PyTuple_Check(argTuple)) {
    PyErr_SetString(PyExc_TypeError, "third argument is not a tuple");
    return NULL;
  }
  Py_ssize_t size = PyTuple_Size(argTuple);
  std::map<const std::string, Command*> commandMap = entity->getNewStyleCommandMap();
  if (commandMap.count(std::string(commandName)) != 1) {
    std::ostringstream oss;
    oss << "'" << entity->getName() << "' entity has no command '" << commandName << "'.";
    PyErr_SetString(PyExc_AttributeError, oss.str().c_str());
    return NULL;
  }
  Command* command = commandMap[std::string(commandName)];
  // Check that tuple size is equal to command number of arguments
  const std::vector<Value::Type> typeVector = command->valueTypes();
  if ((unsigned)size != typeVector.size()) {
    std::stringstream ss;
    ss << "command takes " << typeVector.size() << " parameters, " << size << " given.";
Guilhem Saurel's avatar
Guilhem Saurel committed
240
    PyErr_SetString(DGPYERROR, ss.str().c_str());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
241 242 243 244 245 246 247 248 249 250 251 252
    return NULL;
  }
  std::vector<Value> valueVector;
  for (Py_ssize_t iParam = 0; iParam < size; iParam++) {
    PyObject* PyValue = PyTuple_GetItem(argTuple, iParam);
    Value::Type valueType = typeVector[iParam];
    try {
      Value value = pythonToValue(PyValue, valueType);
      valueVector.push_back(value);
    } catch (const std::exception& exc) {
      std::stringstream ss;
      ss << "while parsing argument " << iParam + 1 << ": expecting " << exc.what() << ".";
Guilhem Saurel's avatar
Guilhem Saurel committed
253
      PyErr_SetString(DGPYERROR, ss.str().c_str());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
254 255
      return NULL;
    } catch (...) {
Guilhem Saurel's avatar
Guilhem Saurel committed
256
      PyErr_SetString(DGPYERROR, "Unknown exception");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
257 258 259 260 261 262 263 264 265 266 267
      return NULL;
    }
  }
  command->setParameterValues(valueVector);
  try {
    Value result = command->execute();
    return valueToPython(result);
  }
  CATCH_ALL_EXCEPTIONS();
  return NULL;
}
268

Guilhem Saurel's avatar
format  
Guilhem Saurel committed
269 270 271 272 273 274 275
PyObject* listCommands(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  if (!PyArg_ParseTuple(args, "O", &object)) {
    return NULL;
  }

  // Retrieve the entity instance
276 277
  if (!PyCapsule_CheckExact(object)) {
    PyErr_SetString(PyExc_TypeError, "function takes a PyCapsule as argument");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
278 279
    return NULL;
  }
280
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
  Entity* entity = (Entity*)pointer;
  typedef std::map<const std::string, command::Command*> CommandMap;
  CommandMap map = entity->getNewStyleCommandMap();
  Py_ssize_t nbCommands = (Py_ssize_t)map.size();
  // Create a tuple of same size as the command map
  PyObject* result = PyTuple_New(nbCommands);
  unsigned int count = 0;
  for (CommandMap::iterator it = map.begin(); it != map.end(); it++) {
    std::string commandName = it->first;
    PyObject* pyName = Py_BuildValue("s", commandName.c_str());
    PyTuple_SET_ITEM(result, count, pyName);
    count++;
  }
  return result;
}
PyObject* getCommandDocstring(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  char* commandName;
  if (!PyArg_ParseTuple(args, "Os", &object, &commandName)) {
    return NULL;
  }
302

Guilhem Saurel's avatar
format  
Guilhem Saurel committed
303
  // Retrieve the entity instance
304
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
Guilhem Saurel committed
305
    PyErr_SetString(DGPYERROR, "first argument is not an object");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
306 307
    return NULL;
  }
308
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
  Entity* entity = (Entity*)pointer;
  typedef std::map<const std::string, command::Command*> commandMap_t;
  typedef std::map<const std::string, command::Command*>::iterator iterator_t;
  commandMap_t map = entity->getNewStyleCommandMap();
  command::Command* command = NULL;
  iterator_t it = map.find(commandName);
  if (it == map.end()) {
    std::ostringstream oss;
    oss << "'" << entity->getName() << "' entity has no command '" << commandName << "'.";
    PyErr_SetString(PyExc_AttributeError, oss.str().c_str());
    return NULL;
  }
  command = it->second;
  std::string docstring = command->getDocstring();
  return Py_BuildValue("s", docstring.c_str());
}

PyObject* getDocString(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  if (!PyArg_ParseTuple(args, "O", &object)) {
    return NULL;
  }

  // Retrieve the entity instance
333
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
Guilhem Saurel committed
334
    PyErr_SetString(DGPYERROR, "first argument is not an object");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
335 336
    return NULL;
  }
337
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
338 339 340 341
  Entity* entity = (Entity*)pointer;
  try {
    return Py_BuildValue("s", entity->getDocString().c_str());
  } catch (const std::exception& exc) {
Guilhem Saurel's avatar
Guilhem Saurel committed
342
    PyErr_SetString(DGPYERROR, exc.what());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
343 344
    return NULL;
  } catch (...) {
Guilhem Saurel's avatar
Guilhem Saurel committed
345
    PyErr_SetString(DGPYERROR, "Unknown exception");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
346 347 348 349 350 351 352 353
    return NULL;
  }
  return NULL;
}

PyObject* display(PyObject* /*self*/, PyObject* args) {
  /* Retrieve the entity instance. */
  PyObject* object = NULL;
354
  if (!PyArg_ParseTuple(args, "O", &object) || (!PyCapsule_CheckExact(object))) {
Guilhem Saurel's avatar
Guilhem Saurel committed
355
    PyErr_SetString(DGPYERROR, "first argument is not an object");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
356 357
    return NULL;
  }
358
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
  Entity* entity = (Entity*)pointer;

  /* Run the display function. */
  std::ostringstream oss;
  entity->display(oss);

  /* Return the resulting string. */
  return Py_BuildValue("s", oss.str().c_str());
}

/**
   \brief Set verbosity Level
*/
PyObject* setLoggerVerbosityLevel(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  PyObject* objectVerbosityLevel = NULL;
  if (!PyArg_ParseTuple(args, "OO", &object, &objectVerbosityLevel)) return NULL;

  // Retrieve the entity instance
378
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
379 380 381 382
    PyErr_SetString(PyExc_TypeError, "First argument should be an object");
    return NULL;
  }

383
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  Entity* entity = (Entity*)pointer;

  // Retrieve object verbosity level
  PyObject* valueOfVerbosityLevel = PyObject_GetAttrString(objectVerbosityLevel, "value");
  long verbosityLevel = PyLong_AsLong(valueOfVerbosityLevel);

  try {
    switch (verbosityLevel) {
      case 0:
        entity->setLoggerVerbosityLevel(VERBOSITY_ALL);
        break;
      case 1:
        entity->setLoggerVerbosityLevel(VERBOSITY_INFO_WARNING_ERROR);
        break;
      case 2:
        entity->setLoggerVerbosityLevel(VERBOSITY_WARNING_ERROR);
        break;
      case 3:
        entity->setLoggerVerbosityLevel(VERBOSITY_ERROR);
        break;
      case 4:
        entity->setLoggerVerbosityLevel(VERBOSITY_NONE);
        break;
      default:
        entity->setLoggerVerbosityLevel(VERBOSITY_NONE);
        break;
410
    }
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
411
  } catch (const std::exception& exc) {
Guilhem Saurel's avatar
Guilhem Saurel committed
412
    PyErr_SetString(DGPYERROR, exc.what());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
413 414
    return NULL;
  } catch (const char* s) {
Guilhem Saurel's avatar
Guilhem Saurel committed
415
    PyErr_SetString(DGPYERROR, s);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
416 417
    return NULL;
  } catch (...) {
Guilhem Saurel's avatar
Guilhem Saurel committed
418
    PyErr_SetString(DGPYERROR, "Unknown exception");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
419 420 421 422 423 424 425 426 427 428 429 430 431 432
    return NULL;
  }

  return Py_BuildValue("");
}

/**
   \brief Get verbosity Level
*/
PyObject* getLoggerVerbosityLevel(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;

  // Retrieve the entity instance
433
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
434 435 436 437
    PyErr_SetString(PyExc_TypeError, "first argument is not an object");
    return NULL;
  }

438
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
  Entity* entity = (Entity*)pointer;

  LoggerVerbosity alv;
  try {
    alv = entity->getLoggerVerbosityLevel();
  }
  CATCH_ALL_EXCEPTIONS();

  int ares = (int)alv;
  return Py_BuildValue("i", ares);
}

/**
   \brief Get stream print period
*/
PyObject* getStreamPrintPeriod(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;

  // Retrieve the entity instance
459
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
460 461 462 463
    PyErr_SetString(PyExc_TypeError, "first argument is not an object");
    return NULL;
  }

464
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
465 466 467 468 469
  Entity* entity = (Entity*)pointer;

  double r;
  try {
    r = entity->getStreamPrintPeriod();
470
  }
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484
  CATCH_ALL_EXCEPTIONS();

  return Py_BuildValue("d", r);
}

/**
   \brief Set print period
*/
PyObject* setStreamPrintPeriod(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  double streamPrintPeriod = 0;
  if (!PyArg_ParseTuple(args, "Od", &object, &streamPrintPeriod)) return NULL;

  // Retrieve the entity instance
485
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
486 487 488 489
    PyErr_SetString(PyExc_TypeError, "First argument should be an object");
    return NULL;
  }

490
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
491 492 493 494 495 496
  Entity* entity = (Entity*)pointer;

  try {
    entity->setStreamPrintPeriod(streamPrintPeriod);

  } catch (const std::exception& exc) {
Guilhem Saurel's avatar
Guilhem Saurel committed
497
    PyErr_SetString(DGPYERROR, exc.what());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
498 499
    return NULL;
  } catch (const char* s) {
Guilhem Saurel's avatar
Guilhem Saurel committed
500
    PyErr_SetString(DGPYERROR, s);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
501 502
    return NULL;
  } catch (...) {
Guilhem Saurel's avatar
Guilhem Saurel committed
503
    PyErr_SetString(DGPYERROR, "Unknown exception");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
504 505 506 507
    return NULL;
  }

  return Py_BuildValue("");
508
}
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
509 510 511 512 513 514 515 516 517

/**
   \brief Get stream print period
*/
PyObject* getTimeSample(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  if (!PyArg_ParseTuple(args, "O", &object)) return NULL;

  // Retrieve the entity instance
518
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
519 520 521 522
    PyErr_SetString(PyExc_TypeError, "first argument is not an object");
    return NULL;
  }

523
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
  Entity* entity = (Entity*)pointer;

  double r;
  try {
    r = entity->getTimeSample();
  }
  CATCH_ALL_EXCEPTIONS();

  return Py_BuildValue("d", r);
}

/**
   \brief Set time sample
*/
PyObject* setTimeSample(PyObject* /*self*/, PyObject* args) {
  PyObject* object = NULL;
  double timeSample;
  if (!PyArg_ParseTuple(args, "Od", &object, &timeSample)) return NULL;

  // Retrieve the entity instance
544
  if (!PyCapsule_CheckExact(object)) {
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
545 546 547 548
    PyErr_SetString(PyExc_TypeError, "First argument should be an object");
    return NULL;
  }

549
  void* pointer = PyCapsule_GetPointer(object, "dynamic_graph.Entity");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
550 551 552 553 554 555
  Entity* entity = (Entity*)pointer;

  try {
    entity->setTimeSample(timeSample);

  } catch (const std::exception& exc) {
Guilhem Saurel's avatar
Guilhem Saurel committed
556
    PyErr_SetString(DGPYERROR, exc.what());
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
557 558
    return NULL;
  } catch (const char* s) {
Guilhem Saurel's avatar
Guilhem Saurel committed
559
    PyErr_SetString(DGPYERROR, s);
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
560 561
    return NULL;
  } catch (...) {
Guilhem Saurel's avatar
Guilhem Saurel committed
562
    PyErr_SetString(DGPYERROR, "Unknown exception");
Guilhem Saurel's avatar
format  
Guilhem Saurel committed
563 564 565 566 567 568 569 570 571
    return NULL;
  }

  return Py_BuildValue("");
}

}  // namespace entity
}  // namespace python
}  // namespace dynamicgraph