GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/dynamic-graph/python/module.hh Lines: 15 17 88.2 %
Date: 2022-09-30 08:22:45 Branches: 12 24 50.0 %

Line Branch Exec Source
1
#ifndef DYNAMIC_GRAPH_PYTHON_MODULE_HH
2
#define DYNAMIC_GRAPH_PYTHON_MODULE_HH
3
4
#ifdef PINOCCHIO_WITH_URDFDOM
5
// If pinocchio is used, we have to include pinocchio header before boost mpl
6
#include <pinocchio/fwd.hpp>
7
#endif
8
9
#include <dynamic-graph/entity.h>
10
11
#include <boost/mpl/for_each.hpp>
12
#include <boost/mpl/vector.hpp>
13
#include <boost/python.hpp>
14
#include <dynamic-graph/python/dynamic-graph-py.hh>
15
16
namespace dynamicgraph {
17
namespace python {
18
19
constexpr int AddSignals = 1;
20
constexpr int AddCommands = 2;
21
22
namespace internal {
23
24
template <typename T, int Options = AddCommands | AddSignals>
25
5
bp::object makeEntity1(const char* name) {
26
5
  Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
27

5
  assert(dynamic_cast<T*>(ent) != NULL);
28
5
  bp::object obj(bp::ptr(static_cast<T*>(ent)));
29

5
  if (Options & AddCommands) entity::addCommands(obj);
30

5
  if (Options & AddSignals) entity::addSignals(obj);
31
5
  return obj;
32
}
33
template <typename T, int Options = AddCommands | AddSignals>
34
bp::object makeEntity2() {
35
  return makeEntity1<T, Options>("");
36
}
37
38
}  // namespace internal
39
40
/// \tparam Options by default, all the signals and commands are added as
41
///         attribute to the Python object. This behaviour works fine for
42
///         entities that have static commands and signals.
43
///         If some commands or signals are added or removed dynamiccally, then
44
///         it is better to disable the default behaviour and handle it
45
///         specifically.
46
template <typename T,
47
          typename bases = boost::python::bases<dynamicgraph::Entity>,
48
          int Options = AddCommands | AddSignals>
49
6
inline auto exposeEntity() {
50
  // std::string hiddenClassName ("_" + T::CLASS_NAME);
51
12
  std::string hiddenClassName(T::CLASS_NAME);
52
  namespace bp = boost::python;
53

6
  bp::class_<T, bases, boost::noncopyable> obj(hiddenClassName.c_str(),
54
                                               bp::init<std::string>());
55
  /* TODO at the moment, I couldn't easily find a way to define a Python
56
  constructor
57
   * that would create the entity via the factory and then populate the
58
   * python object with its commands.
59
   * This is achieved with a factory function of the same name.
60
  obj.def ("__init__", bp::raw_function(+[](bp::object args, bp::dict) {
61
          if (bp::len(args) != 2)
62
            throw std::length_error("Expected 2 arguments.");
63
          bp::object self = args[0];
64
          self.attr("__init__")(bp::extract<std::string>(args[1]));
65
          Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
66
          if (dynamic_cast<T*>(ent) == NULL)
67
            std::cout << "foo" << std::endl;
68
          assert(dynamic_cast<T*>(ent) != NULL);
69
          self = bp::object(bp::ptr(static_cast<T*>(ent)));
70
          //dynamicgraph::Entity& unused =
71
  bp::extract<dynamicgraph::Entity&>(self);
72
          //entity::addCommands(self);
73
        })
74
  ;
75
  */
76
6
  bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity1<T, Options>);
77
6
  bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity2<T, Options>);
78
4
  if (!(Options & AddCommands)) obj.def("add_commands", &entity::addCommands);
79
4
  if (!(Options & AddSignals)) obj.def("add_signals", &entity::addSignals);
80
12
  return obj;
81
}
82
83
}  // namespace python
84
}  // namespace dynamicgraph
85
86
#endif  // DYNAMIC_GRAPH_PYTHON_MODULE_HH