Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ostasse/dynamic-graph-python
  • gsaurel/dynamic-graph-python
  • stack-of-tasks/dynamic-graph-python
3 results
Show changes
Showing
with 704 additions and 2141 deletions
......@@ -4,29 +4,23 @@
#ifndef DGPY_SIGNAL_WRAPPER
#define DGPY_SIGNAL_WRAPPER
#include <dynamic-graph/entity.h>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/signal.h>
#include <dynamic-graph/entity.h>
#include <boost/bind.hpp>
#include <boost/python.hpp>
#include "dynamic-graph/python/python-compat.hh"
namespace dynamicgraph {
namespace python {
namespace signalWrapper {
void convert(PyObject* o, int& v);
void convert(PyObject* o, bool& v);
void convert(PyObject* o, float& v);
void convert(PyObject* o, double& v);
// void convert (PyObject* o, std::string& v);
void convert(PyObject* o, Vector& v);
// void convert (PyObject* o, Eigen::MatrixXd& v);
// void convert (PyObject* o, Eigen::Matrix4d& v);
} // namespace signalWrapper
class PythonSignalContainer : public Entity {
DYNAMIC_GRAPH_ENTITY_DECL();
public:
PythonSignalContainer(const std::string& name);
using Entity::Entity;
void signalRegistration(const SignalArray<int>& signals);
......@@ -37,17 +31,18 @@ template <class T, class Time>
class SignalWrapper : public Signal<T, Time> {
public:
typedef Signal<T, Time> parent_t;
typedef boost::python::object pyobject;
static bool checkCallable(PyObject* c, std::string& error);
static bool checkCallable(pyobject c, std::string& error);
SignalWrapper(std::string name, PyObject* _callable) : parent_t(name), callable(_callable) {
SignalWrapper(std::string name, pyobject callable)
: parent_t(name), callable(callable) {
typedef boost::function2<T&, T&, Time> function_t;
Py_INCREF(callable);
function_t f = boost::bind(&SignalWrapper::call, this, _1, _2);
this->setFunction(f);
}
virtual ~SignalWrapper() { Py_DECREF(callable); };
virtual ~SignalWrapper(){};
private:
T& call(T& value, Time t) {
......@@ -56,18 +51,12 @@ class SignalWrapper : public Signal<T, Time> {
if (PyGILState_GetThisThreadState() == NULL) {
dgDEBUG(10) << "python thread not initialized" << std::endl;
}
char format[] = "i";
PyObject* obj = PyObject_CallFunction(callable, format, t);
if (obj == NULL) {
dgERROR << "Could not call callable" << std::endl;
} else {
signalWrapper::convert(obj, value);
Py_DECREF(obj);
}
pyobject obj = callable(t);
value = boost::python::extract<T>(obj);
PyGILState_Release(gstate);
return value;
}
PyObject* callable;
pyobject callable;
};
} // namespace python
......
// Copyright 2020, Joseph Mirabel, LAAS-CNRS.
#include <dynamic-graph/signal-base.h>
#include <dynamic-graph/signal-ptr.h>
#include <dynamic-graph/signal-time-dependent.h>
#include <dynamic-graph/signal.h>
#include <boost/python.hpp>
#include <sstream>
#include "dynamic-graph/python/signal-wrapper.hh"
namespace dynamicgraph {
namespace python {
template <typename T, typename Time>
auto exposeSignal(const std::string& name) {
namespace bp = boost::python;
typedef Signal<T, Time> S_t;
bp::class_<S_t, bp::bases<SignalBase<Time> >, boost::noncopyable> obj(
name.c_str(), bp::init<std::string>());
obj.add_property(
"value",
bp::make_function(&S_t::accessCopy,
bp::return_value_policy<bp::copy_const_reference>()),
&S_t::setConstant, // TODO check the setter
"the signal value.\n"
"warning: for Eigen objects, sig.value[0] = 1. may not work).");
return obj;
}
template <typename T, typename Time>
auto exposeSignalWrapper(const std::string& name) {
namespace bp = boost::python;
typedef SignalWrapper<T, Time> S_t;
bp::class_<S_t, bp::bases<Signal<T, Time> >, boost::noncopyable> obj(
name.c_str(), bp::no_init);
return obj;
}
template <typename T, typename Time>
auto exposeSignalPtr(const std::string& name) {
namespace bp = boost::python;
typedef SignalPtr<T, Time> S_t;
bp::class_<S_t, bp::bases<Signal<T, Time> >, boost::noncopyable> obj(
name.c_str(), bp::no_init);
return obj;
}
template <typename T, typename Time>
auto exposeSignalTimeDependent(const std::string& name) {
namespace bp = boost::python;
typedef SignalTimeDependent<T, Time> S_t;
bp::class_<S_t, bp::bases<Signal<T, Time> >, boost::noncopyable> obj(
name.c_str(), bp::no_init);
return obj;
}
template <typename T, typename Time>
void exposeSignalsOfType(const std::string& name) {
exposeSignal<T, Time>("Signal" + name);
exposeSignalPtr<T, Time>("SignalPtr" + name);
exposeSignalWrapper<T, Time>("SignalWrapper" + name);
exposeSignalTimeDependent<T, Time>("SignalTimeDependent" + name);
}
} // namespace python
} // namespace dynamicgraph
<?xml version="1.0"?>
<package format="3">
<name>dynamic-graph-python</name>
<version>3.5.2</version>
<description>
Dynamic graph library Python bindings
</description>
<maintainer email="ostasse@laas.fr">Olivier Stasse</maintainer>
<license>BSD</license>
<url>http://github.com/stack-of-tasks/dynamic-graph-python</url>
<version>4.0.11</version>
<description>Dynamic graph library Python bindings</description>
<maintainer email="guilhem.saurel@laas.fr">Guilhem Saurel</maintainer>
<author>Nicolas Mansard</author>
<author>Olivier Stasse</author>
<license>BSD</license>
<url type="website">https://github.com/stack-of-tasks/dynamic-graph-python</url>
<build_depend>git</build_depend>
<build_depend>doxygen</build_depend>
<doc_depend>doxygen</doc_depend>
<!-- The following tags are recommended by REP-136 -->
<!-- The following tag is recommended by REP-136 -->
<exec_depend condition="$ROS_VERSION == 1">catkin</exec_depend>
<exec_depend condition="$ROS_VERSION == 2">ament_cmake</exec_depend>
<depend>dynamic-graph</depend>
<depend>roscpp</depend>
<depend condition="$ROS_PYTHON_VERSION == 2">python</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3</depend>
<depend condition="$ROS_PYTHON_VERSION == 2">python-numpy</depend>
<depend condition="$ROS_PYTHON_VERSION == 3">python3-numpy</depend>
<depend>eigen</depend>
<depend>boost</depend>
<buildtool_depend>cmake</buildtool_depend>
<depend>eigenpy</depend>
<depend>dynamic-graph</depend>
<buildtool_depend>cmake</buildtool_depend>
<export>
<build_type>cmake</build_type>
</export>
</package>
[tool.black]
exclude = "cmake"
extend-exclude = "tests/test_python-syntax_error.py"
[flake8]
exclude = cmake,tests/test_python-syntax_error.py
max-line-length = 88
ignore = E226, E704, E24, E121, W504, E126, E123, W503, E203
# Python bindings
# Python bindings
ADD_SUBDIRECTORY(dynamic_graph)
add_subdirectory(dynamic_graph)
SET(PYTHON_SOURCES
__init__.py
attrpath.py
entity.py
signal_base.py
script_shortcuts.py
tools.py
)
set(PYTHON_SOURCES __init__.py attrpath.py entity.py signal_base.py
script_shortcuts.py tools.py)
FOREACH(source ${PYTHON_SOURCES})
PYTHON_INSTALL_ON_SITE(dynamic_graph ${source})
ENDFOREACH(source)
foreach(source ${PYTHON_SOURCES})
python_install_on_site(dynamic_graph ${source})
endforeach(source)
# --- ADD the wrap on the dg modules
LINK_DIRECTORIES(${DYNAMIC_GRAPH_PLUGINDIR})
DYNAMIC_GRAPH_PYTHON_MODULE("tracer" dynamic-graph::tracer tracer-wrap)
DYNAMIC_GRAPH_PYTHON_MODULE("tracer_real_time" dynamic-graph::tracer-real-time
tracer_real_time-wrap)
link_directories(${DYNAMIC_GRAPH_PLUGINDIR})
dynamic_graph_python_module(
"tracer" dynamic-graph::tracer tracer-wrap SOURCE_PYTHON_MODULE
${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/tracer/wrap.cc)
dynamic_graph_python_module(
"tracer_real_time" dynamic-graph::tracer-real-time tracer_real_time-wrap
SOURCE_PYTHON_MODULE
${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/tracer_real_time/wrap.cc)
# Copyright 2010-2020, Florent Lamiraux, Thomas Moulard, Olivier Stasse, Guilhem Saurel, JRL, CNRS/AIST, LAAS-CNRS
# Copyright 2010-2021, Florent Lamiraux, Thomas Moulard, Olivier Stasse, Guilhem
# Saurel, JRL, CNRS/AIST, LAAS-CNRS
SET(PYTHON_MODULE wrap)
set(PYTHON_MODULE wrap)
ADD_LIBRARY(${PYTHON_MODULE} MODULE
convert-dg-to-py.cc
debug-py.cc
dynamic-graph-py.cc
entity-py.cc
exception-python.cc
factory-py.cc
pool-py.cc
python-compat.cc
signal-base-py.cc
signal-caster-py.cc
signal-wrapper.cc
)
add_library(
${PYTHON_MODULE} MODULE debug-py.cc dynamic-graph-py.cc factory-py.cc
pool-py.cc signal-base-py.cc signal-wrapper.cc)
TARGET_INCLUDE_DIRECTORIES(${PYTHON_MODULE} SYSTEM PUBLIC ${PYTHON_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${PYTHON_LIBRARY}
dynamic-graph::dynamic-graph)
target_link_libraries(${PYTHON_MODULE} PUBLIC ${PROJECT_NAME} eigenpy::eigenpy)
# Remove prefix lib
SET_TARGET_PROPERTIES(${PYTHON_MODULE} PROPERTIES PREFIX "")
set_target_properties(${PYTHON_MODULE} PROPERTIES PREFIX "")
INSTALL(TARGETS ${PYTHON_MODULE}
if(UNIX AND NOT APPLE)
set_target_properties(${PYTHON_MODULE} PROPERTIES INSTALL_RPATH
"\$ORIGIN/../../..")
endif()
install(
TARGETS ${PYTHON_MODULE}
EXPORT ${TARGETS_EXPORT_NAME}
DESTINATION ${PYTHON_SITELIB}/dynamic_graph)
......@@ -5,31 +5,6 @@ Author: Florent Lamiraux
from __future__ import print_function
import sys
from . import entity # noqa
from . import signal_base # noqa
try:
from DLFCN import RTLD_NOW, RTLD_GLOBAL
except ModuleNotFoundError: # Python 3
from os import RTLD_NOW, RTLD_GLOBAL
flags = sys.getdlopenflags()
# Import C++ symbols in a global scope
# This is necessary for signal compiled in different modules to be compatible
sys.setdlopenflags(RTLD_NOW | RTLD_GLOBAL)
from .wrap import * # noqa
# Recover previous flags
sys.setdlopenflags(flags)
def plug(signalOut, signalIn):
"""
Plug an output signal into an input signal
"""
# get signals and entities
w_plug(signalOut.obj, signalIn.obj) # noqa
......@@ -18,10 +18,11 @@ class CommandPath(object):
to store entity commands. It has no members except those automatically
defined at run time (which should be CommandPath or functions).
"""
mother = None
def __getattr__(self, name):
privateName = name + '_obj'
privateName = name + "_obj"
if privateName in self.__dict__:
obj = getattr(self, privateName)
obj.mother = self.mother
......@@ -38,7 +39,7 @@ def createCommandModule(target, name):
return __
privateName = name + '_obj'
privateName = name + "_obj"
setattr(target, privateName, CommandPath())
if not isinstance(target, CommandPath):
......@@ -46,8 +47,8 @@ def createCommandModule(target, name):
class CommandLauncher(object):
"""
"""
""" """
mother = None
fun = None
......@@ -60,7 +61,7 @@ class CommandLauncher(object):
def createCommandLauncher(target, name, fun):
if isinstance(target, CommandPath):
privateName = name + '_obj'
privateName = name + "_obj"
setattr(target, privateName, CommandLauncher(fun))
else:
setattr(target, name, fun)
......@@ -74,7 +75,7 @@ def setattrpath(target, path, attribute):
pathk = target
read = True
if isinstance(path, str):
path = path.split('.')
path = path.split(".")
for tokenk in path[0:-1]:
if (not read) | (tokenk not in pathk.__dict__):
read = False
......@@ -94,7 +95,7 @@ def getattrpath(target, path):
"""
pathk = target
if isinstance(path, str):
path = path.split('.')
path = path.split(".")
for tokenk in path:
privateName = tokenk + "_obj"
if hasattr(pathk, privateName):
......@@ -103,7 +104,12 @@ def getattrpath(target, path):
if hasattr(pathk, tokenk):
pathk = getattr(pathk, tokenk)
else:
raise Exception('Path does not exist -- while accessing "' + tokenk + '" in ' + '.'.join(path))
raise Exception(
'Path does not exist -- while accessing "'
+ tokenk
+ '" in '
+ ".".join(path)
)
return pathk
......@@ -114,11 +120,11 @@ def existattrpath(target, path):
"""
pathk = target
if isinstance(path, str):
path = path.split('.')
path = path.split(".")
for tokenk in path[0:-1]:
print('check ', tokenk)
print("check ", tokenk)
privateName = tokenk + "_obj"
if (privateName not in pathk.__dict__):
if privateName not in pathk.__dict__:
return False
pathk = getattr(pathk, privateName)
name = path[-1]
......
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/convert-dg-to-py.hh"
#include <dynamic-graph/signal-base.h>
#include <dynamic-graph/signal.h>
#include <dynamic-graph/signal-caster.h>
#include <dynamic-graph/signal.h>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/convert-dg-to-py.hh"
#include "dynamic-graph/python/python-compat.hh"
namespace dynamicgraph {
......@@ -17,209 +20,39 @@ using ::dynamicgraph::SignalBase;
namespace python {
namespace convert {
void fillMatrixRow(Matrix& m, unsigned iRow, PyObject* sequence) {
if (PySequence_Size(sequence) != (int)m.cols()) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "lines of matrix have different sizes.");
}
for (int iCol = 0; iCol < m.cols(); iCol++) {
PyObject* pyDouble = PySequence_GetItem(sequence, iCol);
if (PyFloat_Check(pyDouble))
m(iRow, iCol) = PyFloat_AsDouble(pyDouble);
else if (PyLong_Check(pyDouble))
m(iRow, iCol) = (int)PyLong_AsLong(pyDouble) + 0.0;
else
throw ExceptionPython(ExceptionPython::MATRIX_PARSING,
"element of matrix should be "
"a floating point number.");
}
}
void fillMatrixRow(Eigen::Matrix4d& m, unsigned iRow, PyObject* sequence) {
if (PySequence_Size(sequence) != (int)m.cols()) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "lines of matrix have different sizes.");
}
for (int iCol = 0; iCol < m.cols(); iCol++) {
PyObject* pyDouble = PySequence_GetItem(sequence, iCol);
if (PyFloat_Check(pyDouble))
m(iRow, iCol) = PyFloat_AsDouble(pyDouble);
else if (PyLong_Check(pyDouble))
m(iRow, iCol) = (int)PyLong_AsLong(pyDouble) + 0.0;
else
throw ExceptionPython(ExceptionPython::MATRIX_PARSING,
"element of matrix should be "
"a floating point number.");
}
}
namespace bp = boost::python;
command::Value pythonToValue(PyObject* pyObject, const command::Value::Type& valueType) {
command::Value toValue(bp::object o, const command::Value::Type& valueType) {
using command::Value;
bool bvalue;
unsigned uvalue;
int ivalue;
float fvalue;
double dvalue;
std::string svalue;
Vector v;
Matrix m;
Eigen::Matrix4d m4;
Py_ssize_t nCols;
Py_ssize_t size;
PyObject* row;
Py_ssize_t nRows;
switch (valueType) {
case (Value::BOOL):
if (!PyBool_Check(pyObject)) {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "bool");
}
bvalue = PyObject_IsTrue(pyObject);
return Value(bvalue);
break;
return Value(bp::extract<bool>(o));
case (Value::UNSIGNED):
if (PyLong_Check(pyObject)) {
uvalue = (unsigned int)PyLong_AsUnsignedLongMask(pyObject);
#if PY_MAJOR_VERSION == 2
} else if (PyInt_Check(pyObject)) {
uvalue = (unsigned int)PyInt_AsUnsignedLongMask(pyObject);
#endif
} else {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "unsigned int");
}
return Value(uvalue);
break;
return Value(bp::extract<unsigned>(o));
case (Value::INT):
if (PyLong_Check(pyObject)) {
ivalue = (int)PyLong_AsLong(pyObject);
#if PY_MAJOR_VERSION == 2
} else if (PyInt_Check(pyObject)) {
ivalue = (int)PyInt_AsLong(pyObject);
#endif
} else {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "int");
}
return Value(ivalue);
break;
return Value(bp::extract<int>(o));
case (Value::FLOAT):
if (PyFloat_Check(pyObject)) {
fvalue = (float)PyFloat_AsDouble(pyObject);
} else if (PyLong_Check(pyObject)) {
fvalue = (float)PyLong_AsLong(pyObject);
#if PY_MAJOR_VERSION == 2
} else if (PyInt_Check(pyObject)) {
fvalue = (float)PyInt_AsLong(pyObject);
#endif
} else {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "float");
}
return Value(fvalue);
break;
return Value(bp::extract<float>(o));
case (Value::DOUBLE):
if (PyFloat_Check(pyObject)) {
dvalue = PyFloat_AsDouble(pyObject);
} else if (PyLong_Check(pyObject)) {
dvalue = (double)PyLong_AsLong(pyObject);
#if PY_MAJOR_VERSION == 2
} else if (PyInt_Check(pyObject)) {
dvalue = (double)PyInt_AsLong(pyObject);
#endif
} else {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "double");
}
return Value(dvalue);
break;
return Value(bp::extract<double>(o));
case (Value::STRING):
if (!PyUnicode_Check(pyObject)
#if PY_MAJOR_VERSION == 2
&& !PyString_Check(pyObject)
#endif
) {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "string");
}
svalue = obj_to_str(pyObject);
return Value(svalue);
break;
return Value(bp::extract<std::string>(o));
case (Value::VECTOR):
// Check that argument is a tuple
if (!PySequence_Check(pyObject)) {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "vector");
}
size = PySequence_Size(pyObject);
v.resize(size);
for (Py_ssize_t i = 0; i < size; i++) {
PyObject* pyDouble = PySequence_GetItem(pyObject, i);
if (PyFloat_Check(pyDouble))
v(i) = PyFloat_AsDouble(pyDouble);
else if (PyLong_Check(pyDouble))
v(i) = (int)PyLong_AsLong(pyDouble) + 0.0;
#if PY_MAJOR_VERSION == 2
else if (PyInt_Check(pyDouble))
v(i) = (int)PyInt_AsLong(pyDouble) + 0.0;
#endif
else
throw ExceptionPython(ExceptionPython::VECTOR_PARSING,
"element of vector should be a floating "
"point number.");
}
return Value(v);
break;
// TODO for backward compatibility, support tuple or list ?
// I don't think so
return Value(bp::extract<Vector>(o));
case (Value::MATRIX):
// Check that argument is a tuple
if (!PySequence_Check(pyObject)) {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "matrix");
}
nRows = PySequence_Size(pyObject);
if (nRows == 0) {
return Value(Matrix());
}
row = PySequence_GetItem(pyObject, 0);
if (!PySequence_Check(row)) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "matrix");
}
nCols = PySequence_Size(row);
m.resize((unsigned int)nRows, (unsigned int)nCols);
fillMatrixRow(m, 0, row);
for (Py_ssize_t iRow = 1; iRow < nRows; iRow++) {
row = PySequence_GetItem(pyObject, iRow);
if (!PySequence_Check(row)) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "matrix");
}
fillMatrixRow(m, static_cast<unsigned>(iRow), row);
}
return Value(m);
break;
// TODO for backward compatibility, support tuple or list ?
// I don't think so
return Value(bp::extract<Matrix>(o));
case (Value::MATRIX4D):
// Check that argument is a tuple
if (!PySequence_Check(pyObject)) {
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "matrix4d");
}
nRows = PySequence_Size(pyObject);
if (nRows == 0) {
return Value(Eigen::Matrix4d());
}
row = PySequence_GetItem(pyObject, 0);
if (!PySequence_Check(row)) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "matrix4d");
}
nCols = PySequence_Size(row);
m4.resize(nRows, nCols);
fillMatrixRow(m4, 0, row);
for (Py_ssize_t iRow = 1; iRow < nRows; iRow++) {
row = PySequence_GetItem(pyObject, iRow);
if (!PySequence_Check(row)) {
throw ExceptionPython(ExceptionPython::MATRIX_PARSING, "matrix");
}
fillMatrixRow(m4, static_cast<unsigned>(iRow), row);
}
return Value(m4);
break;
return Value(bp::extract<Eigen::Matrix4d>(o));
case (Value::VALUES):
// TODO the vector of values cannot be built since
// - the value type inside the vector are not know
// - inferring the value type from the Python type is not implemented.
throw ExceptionPython(ExceptionPython::VALUE_PARSING, "not implemented: cannot create a vector of values");
throw std::invalid_argument(
"not implemented: cannot create a vector of values");
break;
default:
std::cerr << "Only int, double and string are supported." << std::endl;
......@@ -227,98 +60,36 @@ command::Value pythonToValue(PyObject* pyObject, const command::Value::Type& val
return Value();
}
PyObject* vectorToPython(const Vector& vector) {
PyObject* tuple = PyTuple_New(vector.size());
for (int index = 0; index < vector.size(); index++) {
PyObject* pyDouble = PyFloat_FromDouble(vector(index));
PyTuple_SET_ITEM(tuple, index, pyDouble);
}
return tuple;
}
PyObject* matrixToPython(const Matrix& matrix) {
PyObject* tuple = PyTuple_New(matrix.rows());
for (int iRow = 0; iRow < matrix.rows(); iRow++) {
PyObject* row = PyTuple_New(matrix.cols());
for (int iCol = 0; iCol < matrix.cols(); iCol++) {
PyObject* pyDouble = PyFloat_FromDouble(matrix(iRow, iCol));
PyTuple_SET_ITEM(row, iCol, pyDouble);
}
PyTuple_SET_ITEM(tuple, iRow, row);
}
return tuple;
}
PyObject* matrix4dToPython(const Eigen::Matrix4d& matrix) {
PyObject* tuple = PyTuple_New(matrix.rows());
for (int iRow = 0; iRow < matrix.rows(); iRow++) {
PyObject* row = PyTuple_New(matrix.cols());
for (int iCol = 0; iCol < matrix.cols(); iCol++) {
PyObject* pyDouble = PyFloat_FromDouble(matrix(iRow, iCol));
PyTuple_SET_ITEM(row, iCol, pyDouble);
}
PyTuple_SET_ITEM(tuple, iRow, row);
}
return tuple;
}
PyObject* valuesToPython(const dynamicgraph::command::Values& vector) {
PyObject* tuple = PyTuple_New(vector.size());
for (std::size_t index = 0; index < vector.size(); index++) {
PyObject* item = valueToPython(vector[index]);
PyTuple_SET_ITEM(tuple, index, item);
}
return tuple;
}
PyObject* valueToPython(const command::Value& value) {
bp::object fromValue(const command::Value& value) {
using command::Value;
bool boolValue;
unsigned unsignedValue;
int intValue;
float floatValue;
double doubleValue;
std::string stringValue;
Vector vectorValue;
Matrix matrixValue;
Eigen::Matrix4d matrix4dValue;
switch (value.type()) {
case (Value::BOOL):
boolValue = value.value();
if (boolValue) {
return PyBool_FromLong(1);
}
return PyBool_FromLong(0);
return bp::object(value.boolValue());
case (Value::UNSIGNED):
unsignedValue = value.value();
return Py_BuildValue("I", unsignedValue);
return bp::object(value.unsignedValue());
case (Value::INT):
intValue = value.value();
return Py_BuildValue("i", intValue);
return bp::object(value.intValue());
case (Value::FLOAT):
floatValue = value.value();
return Py_BuildValue("f", floatValue);
return bp::object(value.floatValue());
case (Value::DOUBLE):
doubleValue = value.value();
return Py_BuildValue("d", doubleValue);
return bp::object(value.doubleValue());
case (Value::STRING):
stringValue = (std::string)value.value();
return Py_BuildValue("s", stringValue.c_str());
return bp::object(value.stringValue());
case (Value::VECTOR):
vectorValue = value.value();
return vectorToPython(vectorValue);
return bp::object(value.vectorValue());
case (Value::MATRIX):
matrixValue = value.value();
return matrixToPython(matrixValue);
return bp::object(value.matrixXdValue());
case (Value::MATRIX4D):
matrix4dValue = value.value();
return matrix4dToPython(matrix4dValue);
case (Value::VALUES):
return valuesToPython(value.constValuesValue());
return bp::object(value.matrix4dValue());
case (Value::VALUES): {
bp::list list;
for (const Value& v : value.constValuesValue()) list.append(fromValue(v));
return list;
}
case (Value::NONE):
default:
return Py_BuildValue("");
return bp::object();
}
return Py_BuildValue("");
}
} // namespace convert
......
......@@ -5,15 +5,14 @@
#include <iostream>
#define ENABLE_RT_LOG
#include <dynamic-graph/entity.h>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/real-time-logger.h>
#include <boost/shared_ptr.hpp>
#include <map>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/entity.h>
#include <vector>
#include "dynamic-graph/python/exception.hh"
#include <boost/shared_ptr.hpp>
#include "dynamic-graph/python/dynamic-graph-py.hh"
typedef boost::shared_ptr<std::ofstream> ofstreamShrPtr;
......@@ -21,108 +20,31 @@ 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(
#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);
try {
std::ofstream* aofs = new std::ofstream;
ofstreamShrPtr ofs_shrptr = boost::shared_ptr<std::ofstream>(aofs);
aofs->open(filename, std::ofstream::out);
dynamicgraph::RealTimeLogger::instance();
dgADD_OSTREAM_TO_RTLOG(*aofs);
dgRTLOG() << "Added " << filename << " as an output stream \n";
mapOfFiles_[sfilename] = ofs_shrptr;
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
void addLoggerFileOutputStream(const char* filename) {
std::ofstream* aofs = new std::ofstream;
ofstreamShrPtr ofs_shrptr = boost::shared_ptr<std::ofstream>(aofs);
aofs->open(filename, std::ofstream::out);
dynamicgraph::RealTimeLogger::instance();
dgADD_OSTREAM_TO_RTLOG(*aofs);
dgRTLOG() << "Added " << filename << " as an output stream \n";
mapOfFiles_[filename] = ofs_shrptr;
}
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(m);
return Py_BuildValue("");
void closeLoggerFileOutputStream() {
for (const auto& el : mapOfFiles_) el.second->close();
}
PyObject* addLoggerCoutOutputStream(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
dgADD_OSTREAM_TO_RTLOG(std::cout);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
void addLoggerCoutOutputStream() { dgADD_OSTREAM_TO_RTLOG(std::cout); }
PyObject* realTimeLoggerDestroy(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::destroy();
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
void realTimeLoggerDestroy() { RealTimeLogger::destroy(); }
PyObject* realTimeLoggerSpinOnce(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::instance().spinOnce();
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
void realTimeLoggerSpinOnce() { RealTimeLogger::instance().spinOnce(); }
PyObject* realTimeLoggerInstance(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
try {
RealTimeLogger::instance();
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
void realTimeLoggerInstance() { RealTimeLogger::instance(); }
} // namespace debug
} // namespace python
......
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/dynamic-graph-py.hh"
#include <dynamic-graph/command.h>
#include <dynamic-graph/debug.h>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/exception-factory.h>
#include <dynamic-graph/factory.h>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/signal-base.h>
#include <dynamic-graph/signal-time-dependent.h>
#include <dynamic-graph/signal.h>
#include <dynamic-graph/tracer.h>
#include "dynamic-graph/python/exception.hh"
#include "dynamic-graph/python/dynamic-graph-py.hh"
#include <Eigen/Geometry>
#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#include <eigenpy/eigenpy.hpp>
#include <eigenpy/geometry.hpp>
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/convert-dg-to-py.hh"
#include "dynamic-graph/python/module.hh"
#include "dynamic-graph/python/signal-wrapper.hh"
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
PyObject* dgpyError;
#endif
/**
\brief plug a signal into another one.
*/
PyObject* plug(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
PyObject* objOut = NULL;
PyObject* objIn = NULL;
void* pObjOut;
void* pObjIn;
if (!PyArg_ParseTuple(args, "OO", &objOut, &objIn)) return NULL;
if (!PyCapsule_CheckExact(objOut)) {
PyErr_SetString(PyExc_TypeError,
"first argument should be a pointer to"
" signalBase<int>.");
return NULL;
}
if (!PyCapsule_CheckExact(objIn)) {
PyErr_SetString(PyExc_TypeError,
"second argument should be a pointer to"
" signalBase<int>.");
return NULL;
}
void plug(SignalBase<int>* signalOut, SignalBase<int>* signalIn) {
signalIn->plug(signalOut);
}
pObjIn = PyCapsule_GetPointer(objIn, "dynamic_graph.Signal");
SignalBase<int>* signalIn = (SignalBase<int>*)pObjIn;
if (signalIn == NULL) {
std::ostringstream oss;
oss << "dynamic_graph.plug(a, b): Argument 'b' must be of type 'dynamic_graph.Signal', but got "
<< PyCapsule_GetName(objIn);
PyErr_SetString(PyExc_TypeError, oss.str().c_str());
return NULL;
}
pObjOut = PyCapsule_GetPointer(objOut, "dynamic_graph.Signal");
SignalBase<int>* signalOut = (SignalBase<int>*)pObjOut;
if (signalOut == NULL) {
std::ostringstream oss;
oss << "dynamic_graph.plug(a, b): Argument 'a' must be of type 'dynamic_graph.Signal', but got "
<< PyCapsule_GetName(objOut);
PyErr_SetString(PyExc_TypeError, oss.str().c_str());
return NULL;
}
std::ostringstream os;
void enableTrace(bool enable, const char* filename) {
if (enable)
DebugTrace::openFile(filename);
else
DebugTrace::closeFile(filename);
}
} // namespace python
} // namespace dynamicgraph
namespace bp = boost::python;
namespace dg = dynamicgraph;
try {
signalIn->plug(signalOut);
typedef bp::return_value_policy<bp::manage_new_object> manage_new_object;
typedef bp::return_value_policy<bp::reference_existing_object>
reference_existing_object;
typedef dg::PoolStorage::Entities MapOfEntities;
struct MapOfEntitiesPairToPythonConverter {
static PyObject* convert(const MapOfEntities::value_type& pair) {
return bp::incref(bp::make_tuple(pair.first, bp::ptr(pair.second)).ptr());
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
};
MapOfEntities* getEntityMap() {
return const_cast<MapOfEntities*>(
&dg::PoolStorage::getInstance()->getEntityMap());
}
dg::SignalBase<int>* getSignal(dg::Entity& e, const std::string& name) {
return &e.getSignal(name);
}
PyObject* enableTrace(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
PyObject* boolean;
char* filename = NULL;
if (PyArg_ParseTuple(args, "Os", &boolean, &filename)) {
if (!PyBool_Check(boolean)) {
PyErr_SetString(PyExc_TypeError,
"enableTrace takes as first "
"argument True or False,\n"
" and as "
"second argument a filename.");
return NULL;
}
if (PyObject_IsTrue(boolean)) {
try {
DebugTrace::openFile(filename);
}
CATCH_ALL_EXCEPTIONS(m);
} else {
try {
DebugTrace::closeFile(filename);
}
CATCH_ALL_EXCEPTIONS(m);
}
} else {
return NULL;
class PythonEntity : public dg::Entity {
DYNAMIC_GRAPH_ENTITY_DECL();
public:
using dg::Entity::Entity;
void signalRegistration(dg::SignalBase<int>& signal) {
dg::Entity::signalRegistration(signal);
}
void signalDeregistration(const std::string& name) {
dg::Entity::signalDeregistration(name);
}
return Py_BuildValue("");
};
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(PythonEntity, "PythonEntity");
void exposeEntityBase() {
using namespace dynamicgraph;
bp::enum_<LoggerVerbosity>("LoggerVerbosity")
.value("VERBOSITY_ALL", VERBOSITY_ALL)
.value("VERBOSITY_INFO_WARNING_ERROR", VERBOSITY_INFO_WARNING_ERROR)
.value("VERBOSITY_WARNING_ERROR", VERBOSITY_WARNING_ERROR)
.value("VERBOSITY_ERROR", VERBOSITY_ERROR)
.value("VERBOSITY_NONE", VERBOSITY_NONE)
.export_values();
bp::class_<Entity, boost::noncopyable>("Entity", bp::no_init)
.add_property("name",
bp::make_function(
&Entity::getName,
bp::return_value_policy<bp::copy_const_reference>()))
.add_property("className",
bp::make_function(
&Entity::getClassName,
bp::return_value_policy<bp::copy_const_reference>()),
"the class name of the Entity")
.add_property("__doc__", &Entity::getDocString)
.def("setLoggerVerbosityLevel", &Entity::setLoggerVerbosityLevel)
.def("getLoggerVerbosityLevel", &Entity::getLoggerVerbosityLevel)
.add_property("loggerVerbosityLevel", &Entity::setLoggerVerbosityLevel,
&Entity::getLoggerVerbosityLevel,
"the verbosity level of the entity")
.def("setTimeSample", &Entity::setTimeSample)
.def("getTimeSample", &Entity::getTimeSample)
.add_property("timeSample", &Entity::getTimeSample,
&Entity::setTimeSample,
"the time sample for printing debugging information")
.def("setStreamPrintPeriod", &Entity::setStreamPrintPeriod)
.def("getStreamPrintPeriod", &Entity::getStreamPrintPeriod)
.add_property("streamPrintPeriod", &Entity::getStreamPrintPeriod,
&Entity::setStreamPrintPeriod,
"set the period at which debugging information are printed")
.def(
"__str__",
+[](const Entity& e) -> std::string {
std::ostringstream os;
e.display(os);
return os.str();
})
.def(
"signals",
+[](const Entity& e) -> bp::list {
bp::list ret;
for (auto& el : e.getSignalMap()) ret.append(bp::ptr(el.second));
return ret;
},
"Return the list of signals.")
//.def("signal", +[](Entity& e, const std::string &name) { return
//&e.getSignal(name); },
// reference_existing_object())
.def("signal", &getSignal, reference_existing_object(),
"get signal by name from an Entity", bp::arg("name"))
.def("hasSignal", &Entity::hasSignal,
"return True if the entity has a signal with the given name")
.def(
"displaySignals",
+[](const Entity& e) {
Entity::SignalMap signals(e.getSignalMap());
std::cout << "--- <" << e.getName();
if (signals.empty())
std::cout << "> has no signal\n";
else
std::cout << "> signal list:\n";
for (const auto& el : signals)
el.second->display(std::cout << " |-- <") << '\n';
},
"Print the list of signals into standard output: temporary.")
/*
.def("__getattr__", +[](Entity& e, const std::string &name) ->
SignalBase<int>* { return &e.getSignal(name); },
reference_existing_object())
def __getattr__(self, name):
try:
return self.signal(name)
except Exception:
try:
object.__getattr__(self, name)
except AttributeError:
raise AttributeError("'%s' entity has no attribute %s\n" %
(self.name, name) + ' entity attributes are usually either\n' + ' -
commands,\n' + ' - signals or,\n' + ' - user defined attributes')
*/
/*
.def("__setattr__", +[](bp::object self, const std::string &name,
bp::object value) { Entity& e = bp::extract<Entity&> (self); if
(e.hasSignal(name)) throw std::invalid_argument(name + " already
designates a signal. " "It is not advised to set a new attribute of the
same name.");
// TODO How do you do that ? I am sure it is possible.
//object.__setattr__(self, name, value)
})
*/
/* TODO ?
def boundNewCommand(self, cmdName):
"""
At construction, all existing commands are bound directly in the
class. This method enables to bound new commands dynamically. These new
bounds are not made with the class, but directly with the object instance.
"""
def boundAllNewCommands(self):
"""
For all commands that are not attribute of the object instance nor of
the class, a new attribute of the instance is created to bound the
command.
"""
*/
// For backward compat
.add_static_property(
"entities",
bp::make_function(&getEntityMap, reference_existing_object()));
python::exposeEntity<PythonEntity, bp::bases<Entity>, 0>()
.def("signalRegistration", &PythonEntity::signalRegistration)
.def("signalDeregistration", &PythonEntity::signalDeregistration);
python::exposeEntity<python::PythonSignalContainer, bp::bases<Entity>, 0>()
.def("rmSignal", &python::PythonSignalContainer::rmSignal,
"Remove a signal", bp::arg("signal_name"));
}
PyObject* error_out(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject*
#else
PyObject*, PyObject*
#endif
) {
PyErr_SetString(DGPYERROR(m), "something bad happened");
return NULL;
void exposeCommand() {
using dg::command::Command;
bp::class_<Command, boost::noncopyable>("Command", bp::no_init)
.def("__call__", bp::raw_function(dg::python::entity::executeCmd, 1),
"execute the command")
.add_property("__doc__", &Command::getDocstring);
}
} // namespace python
} // namespace dynamicgraph
void exposeOldAPI() {
bp::def("plug", dynamicgraph::python::plug,
"plug an output signal into an input signal",
(bp::arg("signalOut"), "signalIn"));
bp::def("enableTrace", dynamicgraph::python::enableTrace,
"Enable or disable tracing debug info in a file");
// Signals
bp::def("create_signal_wrapper",
dynamicgraph::python::signalBase::createSignalWrapper,
reference_existing_object(), "create a SignalWrapper C++ object");
// Entity
bp::def("factory_get_entity_class_list",
dynamicgraph::python::factory::getEntityClassList,
"return the list of entity classes");
bp::def("writeGraph", dynamicgraph::python::pool::writeGraph,
"Write the graph of entities in a filename.");
bp::def("get_entity_list", dynamicgraph::python::pool::getEntityList,
"return the list of instanciated entities");
bp::def("addLoggerFileOutputStream",
dynamicgraph::python::debug::addLoggerFileOutputStream,
"add a output file stream to the logger by filename");
bp::def("addLoggerCoutOutputStream",
dynamicgraph::python::debug::addLoggerCoutOutputStream,
"add std::cout as output stream to the logger");
bp::def("closeLoggerFileOutputStream",
dynamicgraph::python::debug::closeLoggerFileOutputStream,
"close all the loggers file output streams.");
bp::def("real_time_logger_destroy",
dynamicgraph::python::debug::realTimeLoggerDestroy,
"Destroy the real time logger.");
bp::def("real_time_logger_spin_once",
dynamicgraph::python::debug::realTimeLoggerSpinOnce,
"Destroy the real time logger.");
bp::def("real_time_logger_instance",
dynamicgraph::python::debug::realTimeLoggerInstance,
"Starts the real time logger.");
}
#ifdef __cplusplus
extern "C" {
#endif
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC PyInit_wrap(void)
#else
void initwrap(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject* m = PyModule_Create(&dynamicgraph::python::dynamicGraphModuleDef);
#else
PyObject* m = Py_InitModule("wrap", dynamicgraph::python::dynamicGraphMethods);
#endif
if (m == NULL) INITERROR;
DGPYERROR(m) = PyErr_NewException(const_cast<char*>("dynamic_graph.dgpyError"), NULL, NULL);
if (DGPYERROR(m) == NULL) {
Py_DECREF(m);
INITERROR;
}
void enableEigenPy() {
eigenpy::enableEigenPy();
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 (!eigenpy::register_symbolic_link_to_registered_type<Eigen::Quaterniond>())
eigenpy::exposeQuaternion();
if (!eigenpy::register_symbolic_link_to_registered_type<Eigen::AngleAxisd>())
eigenpy::exposeAngleAxis();
#if PY_MAJOR_VERSION >= 3
return m;
#endif
eigenpy::enableEigenPySpecific<Eigen::Matrix4d>();
}
#ifdef __cplusplus
} // extern "C"
#endif
BOOST_PYTHON_MODULE(wrap) {
enableEigenPy();
exposeOldAPI();
dg::python::exposeSignals();
exposeEntityBase();
exposeCommand();
typedef dg::PoolStorage::Entities MapOfEntities;
bp::class_<MapOfEntities>("MapOfEntities")
.def("__len__", &MapOfEntities::size)
.def(
"keys",
+[](const MapOfEntities& m) -> bp::tuple {
bp::list res;
for (const auto& el : m) res.append(el.first);
return bp::tuple(res);
})
.def(
"values",
+[](const MapOfEntities& m) -> bp::tuple {
bp::list res;
for (const auto& el : m) res.append(bp::ptr(el.second));
return bp::tuple(res);
})
.def("__getitem__",
static_cast<dg::Entity*& (MapOfEntities::*)(const std::string& k)>(
&MapOfEntities::at),
reference_existing_object())
.def(
"__setitem__", +[](MapOfEntities& m, const std::string& n,
dg::Entity* e) { m.emplace(n, e); })
.def("__iter__", bp::iterator<MapOfEntities>())
.def(
"__contains__",
+[](const MapOfEntities& m, const std::string& n) -> bool {
return m.count(n);
});
bp::to_python_converter<MapOfEntities::value_type,
MapOfEntitiesPairToPythonConverter>();
}
This diff is collapsed.
"""
Copyright (C) 2010 CNRS
# Copyright (C) 2020 CNRS
#
# Author: Florent Lamiraux, Nicolas Mansard
Author: Florent Lamiraux, Nicolas Mansard
"""
from __future__ import print_function
import types
from enum import Enum
from . import signal_base, wrap
from .attrpath import setattrpath
if 'display' not in globals().keys():
def display(s):
print(s)
# --- FACTORY ------------------------------------------------------------------
class PyEntityFactoryClass(type):
"""
The class build dynamically a new class type, and return the reference
on the class-type object. The class type is not added to any context.
"""
def __new__(factory, className, bases=(), dict={}):
if len(bases) == 0:
# Initialize a basic Entity class
EntityClass = type.__new__(factory, className, (Entity, ), dict)
EntityClass.className = className
EntityClass.__init__ = Entity.initEntity
else:
# Initialize a heritated class
EntityClass = type.__new__(factory, className, bases, dict)
for c in bases:
if issubclass(c, Entity):
EntityClass.className = c.className
break
EntityClass.commandCreated = False
return EntityClass
def PyEntityFactory(className, context):
"""
Build a new class type by calling the factory, and add it
to the given context.
"""
EntityClass = PyEntityFactoryClass(className)
context[className] = EntityClass
return EntityClass
def updateEntityClasses(dictionary):
"""
For all c++entity types that are not in the pyentity class list
(entityClassNameList) run the factory and store the new type in the given
context (dictionary).
"""
cxx_entityList = wrap.factory_get_entity_class_list()
for e in filter(lambda x: x not in Entity.entityClassNameList, cxx_entityList):
# Store new class in dictionary with class name
PyEntityFactory(e, dictionary)
# Store class name in local list
Entity.entityClassNameList.append(e)
# --- ENTITY -------------------------------------------------------------------
class VerbosityLevel(Enum):
"""
Enum class for setVerbosityLevel
"""
VERBOSITY_ALL = 8
VERBOSITY_INFO_WARNING_ERROR = 4
VERBOSITY_WARNING_ERROR = 2
VERBOSITY_ERROR = 1
VERBOSITY_NONE = 0
class Entity(object):
"""
This class binds dynamicgraph::Entity C++ class
"""
obj = None
"""
Store list of entities created via python
"""
entities = dict()
def __init__(self, className, instanceName):
"""
Constructor: if not called by a child class, create and store a pointer
to a C++ Entity object.
"""
object.__setattr__(self, 'obj', wrap.create_entity(className, instanceName))
Entity.entities[instanceName] = self
@staticmethod
def initEntity(self, name):
"""
Common constructor of specialized Entity classes. This function is bound
by the factory to each new class derivated from the Entity class as the
constructor of the new class.
"""
Entity.__init__(self, self.className, name)
if not self.__class__.commandCreated:
self.boundClassCommands()
self.__class__.__doc__ = wrap.entity_get_docstring(self.obj)
self.__class__.commandCreated = True
@property
def name(self):
return wrap.entity_get_name(self.obj)
@property
def className(self):
return wrap.entity_get_class_name(self.obj)
def __str__(self):
return wrap.display_entity(self.obj)
def signal(self, name):
"""
Get a signal of the entity from signal name
"""
signalPt = wrap.entity_get_signal(self.obj, name)
return signal_base.SignalBase(name="", obj=signalPt)
def hasSignal(self, name):
"""
Indicates if a signal with the given name exists in the entity
"""
return wrap.entity_has_signal(self.obj, name)
def displaySignals(self):
"""
Print the list of signals into standard output: temporary.
"""
signals = list(self.signals())
if len(signals) == 0:
display("--- <" + self.name + "> has no signal")
else:
display("--- <" + self.name + "> signal list: ")
for s in signals[:-1]:
display(" |-- <" + str(s))
display(" `-- <" + str(signals[-1]))
def signals(self):
"""
Return the list of signals
"""
sl = wrap.entity_list_signals(self.obj)
return map(lambda pyObj: signal_base.SignalBase(obj=pyObj), sl)
def commands(self):
"""
Return the list of commands.
"""
return wrap.entity_list_commands(self.obj)
def globalHelp(self):
"""
Print a short description of each command.
"""
if self.__doc__:
print(self.__doc__)
print("List of commands:")
print("-----------------")
for cstr in self.commands():
ctitle = cstr + ':'
for i in range(len(cstr), 15):
ctitle += ' '
for docstr in wrap.entity_get_command_docstring(self.obj, cstr).split('\n'):
if (len(docstr) > 0) and (not docstr.isspace()):
display(ctitle + "\t" + docstr)
break
def help(self, comm=None):
"""
With no arg, print the global help. With arg the name of
a specific command, print the help associated to the command.
"""
if comm is None:
self.globalHelp()
else:
display(comm + ":\n" + wrap.entity_get_command_docstring(self.obj, comm))
def __getattr__(self, name):
try:
return self.signal(name)
except Exception:
try:
object.__getattr__(self, name)
except AttributeError:
raise AttributeError("'%s' entity has no attribute %s\n" % (self.name, name) +
' entity attributes are usually either\n' + ' - commands,\n' +
' - signals or,\n' + ' - user defined attributes')
def __setattr__(self, name, value):
if name in map(lambda s: s.getName().split(':')[-1], self.signals()):
raise NameError(name + " already designates a signal. "
"It is not advised to set a new attribute of the same name.")
object.__setattr__(self, name, value)
# --- COMMANDS BINDER -----------------------------------------------------
# List of all the entity classes from the c++ factory, that have been bound
# bind the py factory.
entityClassNameList = []
# This function dynamically create the function object that runs the command.
@staticmethod
def createCommandBind(name, docstring):
def commandBind(self, *arg):
return wrap.entity_execute_command(self.obj, name, arg)
commandBind.__doc__ = docstring
return commandBind
def boundClassCommands(self):
"""
This static function has to be called from a class heritating from Entity.
It should be called only once. It parses the list of commands obtained from
c++, and bind each of them to a python class method.
"""
# Get list of commands of the Entity object
commands = wrap.entity_list_commands(self.obj)
# for each command, add a method with the name of the command
for cmdstr in commands:
docstr = wrap.entity_get_command_docstring(self.obj, cmdstr)
cmdpy = Entity.createCommandBind(cmdstr, docstr)
setattrpath(self.__class__, cmdstr, cmdpy)
def boundNewCommand(self, cmdName):
"""
At construction, all existing commands are bound directly in the class.
This method enables to bound new commands dynamically. These new bounds
are not made with the class, but directly with the object instance.
"""
if (cmdName in self.__dict__) | (cmdName in self.__class__.__dict__):
print("Warning: command ", cmdName, " will overwrite an object attribute.")
docstring = wrap.entity_get_command_docstring(self.obj, cmdName)
cmd = Entity.createCommandBind(cmdName, docstring)
# Limitation (todo): does not handle for path attribute name (see setattrpath).
setattr(self, cmdName, types.MethodType(cmd, self))
def boundAllNewCommands(self):
"""
For all commands that are not attribute of the object instance nor of the
class, a new attribute of the instance is created to bound the command.
"""
cmdList = wrap.entity_list_commands(self.obj)
cmdList = filter(lambda x: x not in self.__dict__, cmdList)
cmdList = filter(lambda x: x not in self.__class__.__dict__, cmdList)
for cmd in cmdList:
self.boundNewCommand(cmd)
def setLoggerVerbosityLevel(self, verbosity):
"""
Specify for the entity the verbosity level.
- param verbosity should be one of the attribute of the enum
dynamic_graph.entity.VerbosityLevel
"""
return wrap.entity_set_logger_verbosity(self.obj, verbosity)
def getLoggerVerbosityLevel(self):
"""
Returns the entity's verbosity level (as a dynamic_graph.entity.VerbosityLevel)
"""
r = wrap.entity_get_logger_verbosity(self.obj)
if r == 8:
return VerbosityLevel.VERBOSITY_ALL
elif r == 4:
return VerbosityLevel.VERBOSITY_INFO_WARNING_ERROR
elif r == 2:
return VerbosityLevel.VERBOSITY_WARNING_ERROR
elif r == 1:
return VerbosityLevel.VERBOSITY_ERROR
return VerbosityLevel.VERBOSITY_NONE
def setTimeSample(self, timeSample):
"""
Specify for the entity the time at which call is counted.
"""
return wrap.entity_set_time_sample(self.obj, timeSample)
def getTimeSample(self):
"""
Returns for the entity the time at which call is counted.
"""
return wrap.entity_get_time_sample(self.obj)
def setStreamPrintPeriod(self, streamPrintPeriod):
"""
Specify for the entity the period at which debugging information is printed
"""
return wrap.entity_set_stream_print_period(self.obj, streamPrintPeriod)
def getStreamPrintPeriod(self):
"""
Returns for the entity the period at which debugging information is printed
"""
return wrap.entity_get_stream_print_period(self.obj)
# for backward compat
from .wrap import LoggerVerbosity as VerbosityLevel # noqa
from .wrap import Entity # noqa
/*
* Copyright 2010,
* François Bleibel,
* Olivier Stasse,
*
* CNRS/AIST
*
*/
#include "dynamic-graph/python/exception-python.hh"
#include <dynamic-graph/debug.h>
#include <stdarg.h>
#include <cstdio>
namespace dynamicgraph {
namespace python {
/* --------------------------------------------------------------------- */
/* --- CLASS ----------------------------------------------------------- */
/* --------------------------------------------------------------------- */
const std::string ExceptionPython::EXCEPTION_NAME = "Python";
ExceptionPython::ExceptionPython(const ExceptionPython::ErrorCodeEnum& errcode, const std::string& msg)
: ExceptionAbstract(errcode, msg) {
dgDEBUGF(15, "Created with message <%s>.", msg.c_str());
dgDEBUG(1) << "Created with message <%s>." << msg << std::endl;
}
ExceptionPython::ExceptionPython(const ExceptionPython::ErrorCodeEnum& errcode, const std::string& msg,
const char* format, ...)
: ExceptionAbstract(errcode, msg) {
va_list args;
va_start(args, format);
const unsigned int SIZE = 256;
char buffer[SIZE];
vsnprintf(buffer, SIZE, format, args);
dgDEBUG(15) << "Created "
<< " with message <" << msg << "> and buffer <" << buffer << ">. " << std::endl;
message += buffer;
va_end(args);
dgDEBUG(1) << "Throw exception " << EXCEPTION_NAME << "[#" << errcode << "]: "
<< "<" << message << ">." << std::endl;
}
} // namespace python
} // namespace dynamicgraph
/*
* Local variables:
* c-basic-offset: 2
* End:
*/
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <iostream>
#include <dynamic-graph/factory.h>
#include <iostream>
#include "dynamic-graph/python/dynamic-graph-py.hh"
using dynamicgraph::Entity;
......@@ -16,22 +17,10 @@ namespace factory {
/**
\brief Get name of entity
*/
PyObject* getEntityClassList(PyObject* /*self*/, PyObject* args) {
if (!PyArg_ParseTuple(args, "")) return NULL;
bp::tuple getEntityClassList() {
std::vector<std::string> classNames;
dynamicgraph::FactoryStorage::getInstance()->listEntities(classNames);
Py_ssize_t classNumber = classNames.size();
// Build a tuple object
PyObject* classTuple = PyTuple_New(classNumber);
for (Py_ssize_t iEntity = 0; iEntity < (Py_ssize_t)classNames.size(); ++iEntity) {
PyObject* className = Py_BuildValue("s", classNames[iEntity].c_str());
PyTuple_SetItem(classTuple, iEntity, className);
}
return Py_BuildValue("O", classTuple);
return to_py_tuple(classNames.begin(), classNames.end());
}
} // namespace factory
......
// Copyright 2011, 2012, Florent Lamiraux, LAAS-CNRS.
#include <dynamic-graph/pool.h>
#include <dynamic-graph/entity.h>
#include <dynamic-graph/pool.h>
#include <vector>
#include "dynamic-graph/python/exception.hh"
#include "dynamic-graph/python/dynamic-graph-py.hh"
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
extern PyObject* dgpyError;
#endif
namespace pool {
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(m);
return Py_BuildValue("");
void writeGraph(const char* filename) {
PoolStorage::getInstance()->writeGraph(filename);
}
const std::map<std::string, Entity*>* getEntityMap() {
return &PoolStorage::getInstance()->getEntityMap();
}
/**
\brief Get list of entities
*/
PyObject* getEntityList(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
if (!PyArg_ParseTuple(args, "")) return NULL;
bp::list getEntityList() {
std::vector<std::string> entityNames;
try {
const PoolStorage::Entities& listOfEntities = dynamicgraph::PoolStorage::getInstance()->getEntityMap();
Py_ssize_t classNumber = listOfEntities.size();
// Build a tuple object
PyObject* classTuple = PyTuple_New(classNumber);
Py_ssize_t iEntity = 0;
for (PoolStorage::Entities::const_iterator entity_it = listOfEntities.begin(); entity_it != listOfEntities.end();
++entity_it) {
const std::string& aname = entity_it->second->getName();
bp::list res;
const PoolStorage::Entities& listOfEntities =
PoolStorage::getInstance()->getEntityMap();
PyObject* className = Py_BuildValue("s", aname.c_str());
PyTuple_SetItem(classTuple, iEntity, className);
iEntity++;
}
return Py_BuildValue("O", classTuple);
}
CATCH_ALL_EXCEPTIONS(m);
return NULL;
for (const auto& el : listOfEntities) res.append(el.second->getName());
return res;
}
} // namespace pool
......
......@@ -14,16 +14,15 @@ from __future__ import print_function
import sys
from .entity import Entity
from .matlab import matlab
from .signal_base import SignalBase
# Enables shortcut "name"
def sig_short_name(self):
return self.getName().split(':')[-1]
return self.getName().split(":")[-1]
setattr(SignalBase, 'name', property(sig_short_name))
setattr(SignalBase, "name", property(sig_short_name))
# Enables shortcuts "m"
......@@ -39,7 +38,7 @@ class PrettySignalPrint:
self.sig = sig
def __str__(self):
return self.sig.name + " = " + str(matlab(self.sig.value))
return self.sig.name + " = " + str(self.sig.value)
def __repr__(self):
return str(self)
......@@ -57,14 +56,12 @@ def sigMatPrint(sig):
return PrettySignalPrint(sig)
setattr(SignalBase, 'm', property(PrettySignalPrint))
# print('Pretty matlab print set')
setattr(SignalBase, "m", property(PrettySignalPrint))
# Enable the same as 'm', but directly on the signal object.
def sigRepr(self):
return self.name + ' = ' + str(matlab(self.value))
return self.name + " = " + str(self.value)
def sigCall(sig, iter):
......@@ -77,9 +74,9 @@ def sigTimeIncr(sig, iter):
print(sigRepr(sig))
setattr(SignalBase, '__repr__', sigRepr)
setattr(SignalBase, '__call__', sigCall)
setattr(SignalBase, '__add__', sigTimeIncr)
setattr(SignalBase, "__repr__", sigRepr)
setattr(SignalBase, "__call__", sigCall)
setattr(SignalBase, "__add__", sigTimeIncr)
# Enables shortcut "deps"
......@@ -100,12 +97,12 @@ class SignalDepPrint:
return self
setattr(SignalBase, 'deps', property(SignalDepPrint))
setattr(SignalBase, "deps", property(SignalDepPrint))
setattr(Entity, 'sigs', property(Entity.displaySignals))
setattr(Entity, '__repr__', Entity.__str__)
setattr(Entity, "sigs", property(Entity.displaySignals))
setattr(Entity, "__repr__", Entity.__str__)
sys.ps1 = '% '
sys.ps1 = "% "
# Enable function that can be call without()def optionalparentheses(f):
......@@ -119,7 +116,7 @@ def optionalparentheses(f):
if isinstance(res, str):
return res
else:
return ''
return ""
def __call__(self, *arg):
return self.functor(*arg)
......
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <iostream>
#include <sstream>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/signal-base.h>
#include <dynamic-graph/signal.h>
#include <dynamic-graph/signal-ptr.h>
#include <dynamic-graph/signal-caster.h>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/pool.h>
#include <dynamic-graph/factory.h>
#include <dynamic-graph/signal-time-dependent.h>
#include <dynamic-graph/signal.h>
#include <dynamic-graph/value.h>
#include <boost/python.hpp>
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/dynamic-graph-py.hh"
#include "dynamic-graph/python/convert-dg-to-py.hh"
#include "dynamic-graph/python/exception.hh"
#include "dynamic-graph/python/signal-wrapper.hh"
#include "dynamic-graph/python/signal.hh"
using dynamicgraph::SignalBase;
namespace bp = boost::python;
namespace dynamicgraph {
namespace python {
#if PY_MAJOR_VERSION == 2
extern PyObject* dgpyError;
#endif
using namespace convert;
namespace signalBase {
typedef int time_type;
typedef Eigen::AngleAxis<double> VectorUTheta;
typedef Eigen::Quaternion<double> Quaternion;
typedef Eigen::VectorXd Vector;
typedef Eigen::Vector3d Vector3;
typedef Eigen::Matrix<double, 7, 1> Vector7;
typedef Eigen::MatrixXd Matrix;
typedef Eigen::Matrix<double, 3, 3> MatrixRotation;
typedef Eigen::Matrix<double, 4, 4> Matrix4;
typedef Eigen::Transform<double, 3, Eigen::Affine> MatrixHomogeneous;
typedef Eigen::Matrix<double, 6, 6> MatrixTwist;
template <typename Time>
void exposeSignalBase(const char* name) {
typedef SignalBase<Time> S_t;
bp::class_<S_t, boost::noncopyable>(name, bp::no_init)
.add_property("time",
bp::make_function(
&S_t::getTime,
bp::return_value_policy<bp::copy_const_reference>()),
&S_t::setTime)
.add_property("name",
bp::make_function(
&S_t::getName,
bp::return_value_policy<bp::copy_const_reference>()))
.def("getName", &S_t::getName,
bp::return_value_policy<bp::copy_const_reference>())
.def(
"getClassName",
+[](const S_t& s) -> std::string {
std::string ret;
s.getClassName(ret);
return ret;
})
.def("plug", &S_t::plug, "Plug the signal to another signal")
.def("unplug", &S_t::unplug, "Unplug the signal")
.def("isPlugged", &S_t::isPlugged, "Whether the signal is plugged")
.def("getPlugged", &S_t::getPluged,
bp::return_value_policy<bp::reference_existing_object>(),
"To which signal the signal is plugged")
.def("recompute", &S_t::recompute, "Recompute the signal at given time")
.def(
"__str__",
+[](const S_t& s) -> std::string {
std::ostringstream oss;
s.display(oss);
return oss.str();
})
.def(
"displayDependencies",
+[](const S_t& s, int time) -> std::string {
std::ostringstream oss;
s.displayDependencies(oss, time);
return oss.str();
},
"Print the signal dependencies in a string");
}
template <>
auto exposeSignal<MatrixHomogeneous, time_type>(const std::string& name) {
typedef Signal<MatrixHomogeneous, time_type> S_t;
bp::class_<S_t, bp::bases<SignalBase<time_type> >, boost::noncopyable> obj(
name.c_str(), bp::init<std::string>());
obj.add_property(
"value",
+[](const S_t& signal) -> Matrix4 {
return signal.accessCopy().matrix();
},
+[](S_t& signal, const Matrix4& v) {
// TODO it isn't hard to support pinocchio::SE3 type here.
// However, this adds a dependency to pinocchio.
signal.setConstant(MatrixHomogeneous(v));
},
"the signal value.");
return obj;
}
static void destroy(PyObject* self);
void exposeSignals() {
exposeSignalBase<time_type>("SignalBase");
/**
\brief Create an instance of SignalBase
*/
PyObject* create(PyObject* /*self*/, PyObject* args) {
char* name = NULL;
exposeSignalsOfType<bool, time_type>("Bool");
exposeSignalsOfType<int, time_type>("Int");
exposeSignalsOfType<double, time_type>("Double");
if (!PyArg_ParseTuple(args, "s", &name)) return NULL;
exposeSignalsOfType<Vector, time_type>("Vector");
exposeSignalsOfType<Vector3, time_type>("Vector3");
exposeSignalsOfType<Vector7, time_type>("Vector7");
SignalBase<int>* obj = NULL;
obj = new SignalBase<int>(std::string(name));
exposeSignalsOfType<Matrix, time_type>("Matrix");
exposeSignalsOfType<MatrixRotation, time_type>("MatrixRotation");
exposeSignalsOfType<MatrixHomogeneous, time_type>("MatrixHomogeneous");
exposeSignalsOfType<MatrixTwist, time_type>("MatrixTwist");
// Return the pointer
return PyCapsule_New((void*)obj, "dynamic_graph.Signal", destroy);
exposeSignalsOfType<Quaternion, time_type>("Quaternion");
exposeSignalsOfType<VectorUTheta, time_type>("VectorUTheta");
}
namespace signalBase {
template <class T>
SignalWrapper<T, int>* createSignalWrapperTpl(const char* name, PyObject* o, std::string& error) {
SignalWrapper<T, int>* createSignalWrapperTpl(const char* name, bp::object o,
std::string& error) {
typedef SignalWrapper<T, int> SignalWrapper_t;
if (!SignalWrapper_t::checkCallable(o, error)) {
return NULL;
......@@ -58,27 +141,7 @@ SignalWrapper<T, int>* createSignalWrapperTpl(const char* name, PyObject* o, std
}
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(m), msg.c_str());
return NULL;
}
} else {
try {
obj = FactoryStorage::getInstance()->newEntity(std::string(className), std::string(instanceName));
}
CATCH_ALL_EXCEPTIONS(m);
}
Entity* obj = entity::create("PythonSignalContainer", "python_signals");
return dynamic_cast<PythonSignalContainer*>(obj);
}
......@@ -90,22 +153,11 @@ PythonSignalContainer* getPythonSignalContainer() {
/**
\brief Create an instance of SignalWrapper
*/
PyObject* createSignalWrapper(
#if PY_MAJOR_VERSION >= 3
PyObject* m, PyObject* args
#else
PyObject*, PyObject* args
#endif
) {
SignalBase<int>* createSignalWrapper(const char* name, const char* type,
bp::object object) {
PythonSignalContainer* psc = getPythonSignalContainer();
if (psc == NULL) return NULL;
char* name = NULL;
char* type = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "ssO", &name, &type, &object)) return NULL;
SignalBase<int>* obj = NULL;
std::string error;
SIGNAL_WRAPPER_TYPE(if, BOOL, bool)
......@@ -121,380 +173,14 @@ PyObject* createSignalWrapper(
error = "Type not understood";
}
if (obj == NULL) {
PyErr_SetString(DGPYERROR(m), error.c_str());
return NULL;
}
if (obj == NULL) throw std::runtime_error(error);
// Register signal into the python signal container
psc->signalRegistration(*obj);
// Return the pointer
return PyCapsule_New((void*)obj, "dynamic_graph.SignalWrapper", destroy);
}
/**
\brief Destroy an instance of InvertedPendulum
*/
static void destroy(PyObject* self) {
SignalBase<int>* obj = (SignalBase<int>*)self;
delete obj;
}
PyObject* getTime(PyObject* /*self*/, PyObject* args) {
void* pointer = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "O", &object)) return NULL;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* obj = (SignalBase<int>*)pointer;
int time = obj->getTime();
return Py_BuildValue("i", time);
}
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(m), "object should be a C object");
return NULL;
}
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* obj = (SignalBase<int>*)pointer;
obj->setTime(time);
return Py_BuildValue("");
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* obj = (SignalBase<int>*)pointer;
std::ostringstream oss;
try {
obj->display(oss);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", oss.str().c_str());
}
PyObject* displayDependencies(
#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)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* obj = (SignalBase<int>*)pointer;
std::ostringstream oss;
try {
obj->displayDependencies(oss, time);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", oss.str().c_str());
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
try {
{ // --- VECTOR SIGNALS -----------------
// Two cases: the signal embeds directly a vector, or embeds
// an object deriving from vector.In the first case,
// the signal is directly cast into sig<vector>.
// In the second case, the derived object can be access as a vector
// using the signal-ptr<vector> type.
Signal<dynamicgraph::Vector, int>* sigvec = dynamic_cast<Signal<dynamicgraph::Vector, int>*>(signal);
if (NULL != sigvec) {
return vectorToPython(sigvec->accessCopy());
}
// Extraction of object derinving from vector: plug signal into
// a vector signal and get the value from the signal-ptr instead
// of the original vector.
SignalPtr<dynamicgraph::Vector, int> sigptr(NULL, "vector-caster");
try {
sigptr.plug(signal);
return vectorToPython(sigptr.accessCopy());
} catch (dynamicgraph::ExceptionSignal& ex) {
if (ex.getCode() != dynamicgraph::ExceptionSignal::PLUG_IMPOSSIBLE) throw;
}
}
{ // --- MATRIX SIGNALS --------------------
// Two cases: the signal embeds directly a matrix, or embeds
// an object deriving from matrix.In the first case,
// the signal is directly cast into sig<matrix>.
// In the second case, the derived object can be access as a matrix
// using the signal-ptr<matrix> type.
Signal<dynamicgraph::Matrix, int>* sigmat = dynamic_cast<Signal<dynamicgraph::Matrix, int>*>(signal);
if (NULL != sigmat) {
return matrixToPython(sigmat->accessCopy());
}
SignalPtr<dynamicgraph::Matrix, int> sigptr(NULL, "matrix-caster");
try {
sigptr.plug(signal);
return matrixToPython(sigptr.accessCopy());
} catch (dynamicgraph::ExceptionSignal& ex) {
if (ex.getCode() != dynamicgraph::ExceptionSignal::PLUG_IMPOSSIBLE) throw;
}
}
{ // --- HOMOGENEOUS MATRIX SIGNALS --------------------
// Two cases: the signal embeds directly a matrix, or embeds
// an object deriving from matrix.In the first case,
// the signal is directly cast into sig<matrix>.
// In the second case, the derived object can be access as a matrix
// using the signal-ptr<matrix> type.
// TODO: See if matrix homogeneous can be properly put in linear-algebra.h
typedef Eigen::Transform<double, 3, Eigen::Affine> MatrixHomogeneous;
Signal<MatrixHomogeneous, int>* sigmat = dynamic_cast<Signal<MatrixHomogeneous, int>*>(signal);
if (NULL != sigmat) {
return matrixToPython(sigmat->accessCopy().matrix());
}
SignalPtr<Eigen::Transform<double, 3, Eigen::Affine>, int> sigptr(NULL, "matrix-caster");
try {
sigptr.plug(signal);
return matrixToPython(sigptr.accessCopy().matrix());
} catch (dynamicgraph::ExceptionSignal& ex) {
if (ex.getCode() != dynamicgraph::ExceptionSignal::PLUG_IMPOSSIBLE) throw;
}
}
Signal<double, int>* sigdouble = dynamic_cast<Signal<double, int>*>(signal);
if (NULL != sigdouble) {
return Py_BuildValue("d", sigdouble->accessCopy());
}
}
CATCH_ALL_EXCEPTIONS(m);
/* Non specific signal: use a generic way. */
std::ostringstream value;
try {
signal->get(value);
}
CATCH_ALL_EXCEPTIONS(m);
std::string valueString = value.str();
return Py_BuildValue("s", valueString.c_str());
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
std::string name;
try {
name = signal->getName();
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", name.c_str());
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
std::string name;
try {
signal->getClassName(name);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("s", name.c_str());
}
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;
if (!PyArg_ParseTuple(args, "Os", &object, &valueString)) return NULL;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
std::ostringstream os;
os << valueString;
std::istringstream value(os.str());
try {
signal->set(value);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
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;
if (!PyArg_ParseTuple(args, "OI", &object, &time)) return NULL;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
try {
signal->recompute(time);
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
try {
signal->unplug();
}
CATCH_ALL_EXCEPTIONS(m);
return Py_BuildValue("");
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
bool plugged = false;
try {
plugged = signal->isPlugged();
}
CATCH_ALL_EXCEPTIONS(m);
if (plugged)
return PyBool_FromLong(1);
else
return PyBool_FromLong(0);
return obj;
}
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;
if (!PyCapsule_CheckExact(object)) return NULL;
pointer = PyCapsule_GetPointer(object, "dynamic_graph.Signal");
SignalBase<int>* signal = (SignalBase<int>*)pointer;
SignalBase<int>* otherSignal = 0;
try {
bool plugged = signal->isPlugged();
otherSignal = signal->getPluged();
if (!plugged || otherSignal == 0) {
std::string msg = std::string("Signal ") + signal->getName() + std::string(" is not plugged.");
throw std::runtime_error(msg);
}
}
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);
}
} // namespace signalBase
} // namespace python
} // namespace dynamicgraph
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <iostream>
#include <sstream>
#include <dynamic-graph/signal-caster.h>
#include "dynamic-graph/python/dynamic-graph-py.hh"
namespace dynamicgraph {
namespace python {
namespace signalCaster {
PyObject* getSignalTypeList(PyObject* /*self*/, PyObject* args) {
if (!PyArg_ParseTuple(args, "")) return NULL;
std::vector<std::string> typeList = dynamicgraph::SignalCaster::getInstance()->listTypenames();
Py_ssize_t typeNumber = typeList.size();
// Build a tuple object
PyObject* typeTuple = PyTuple_New(typeNumber);
for (Py_ssize_t iType = 0; iType < typeNumber; ++iType) {
PyObject* className = Py_BuildValue("s", typeList[iType].c_str());
PyTuple_SetItem(typeTuple, iType, className);
}
return Py_BuildValue("O", typeTuple);
}
} // namespace signalCaster
} // namespace python
} // namespace dynamicgraph