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 731 additions and 539 deletions
# -*- coding: utf-8 -*-
#
# @PROJECT_NAME@ documentation build configuration file, created by
# sphinx-quickstart on Mon Nov 22 16:45:27 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path = [os.path.abspath('@CMAKE_BINARY_DIR@/src')]+sys.path
sys.path = [os.path.abspath('@CMAKE_SOURCE_DIR@/src')]+sys.path
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'@PROJECT_NAME@'
copyright = u'2010, Florent Lamiraux'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = '@PROJECT_NAME@doc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', '@PROJECT_NAME@.tex', u'@PROJECT_NAME@ Documentation',
u'Florent Lamiraux', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}
.. dynamic-graph-python documentation master file, created by
sphinx-quickstart on Mon Nov 22 16:45:27 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to dynamic-graph-python's documentation!
================================================
.. toctree::
:maxdepth: 2
Python module dynamic_graph implements bindings for dynamic-graph_ library. To each main C++ class is associated a Python class. Main classes are listed below.
Entity
------
maps dynamicgraph::Entity_ C++ class.
.. autoclass:: dynamic_graph.entity.Entity
:members:
SignalBase
----------
maps dynamicgraph::SignalBase_ C++ class.
.. autoclass:: dynamic_graph.signal_base.SignalBase
:members:
Other funtions of the module
----------------------------
.. automodule:: dynamic_graph
:members:
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. _dynamic-graph: file://@DYNAMIC_GRAPH_DOXYGENDOCDIR@/index.html
.. _Entity: file://@DYNAMIC_GRAPH_DOXYGENDOCDIR@/classdynamicgraph_1_1_entity.html
.. _SignalBase: file://@DYNAMIC_GRAPH_DOXYGENDOCDIR@/classdynamicgraph_1_1_signal_base.html
// -*- mode: c++ -*-
// Copyright 2011, Florent Lamiraux, CNRS.
#ifndef DYNAMIC_GRAPH_PYTHON_API_HH
#define DYNAMIC_GRAPH_PYTHON_API_HH
#include <dynamic-graph/python/config.hh>
#endif // DYNAMIC_GRAPH_PYTHON_API_HH
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/value.h>
#include <boost/python.hpp>
namespace dynamicgraph {
namespace python {
namespace convert {
command::Value toValue(boost::python::object o,
const command::Value::Type& type);
boost::python::object fromValue(const command::Value& value);
} // namespace convert
} // namespace python
} // namespace dynamicgraph
#ifndef DYNAMIC_GRAPH_PY
#define DYNAMIC_GRAPH_PY
#include <dynamic-graph/debug.h>
#include <dynamic-graph/exception-factory.h>
#include <dynamic-graph/signal-base.h>
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <iostream>
#include <sstream>
#include "dynamic-graph/python/signal-wrapper.hh"
namespace bp = boost::python;
namespace dynamicgraph {
namespace python {
template <typename Iterator>
inline bp::list to_py_list(Iterator begin, Iterator end) {
typedef typename Iterator::value_type T;
bp::list lst;
std::for_each(begin, end, [&](const T& t) { lst.append(t); });
return lst;
}
template <typename Iterator>
inline bp::tuple to_py_tuple(Iterator begin, Iterator end) {
return bp::tuple(to_py_list(begin, end));
}
template <typename T>
inline std::vector<T> to_std_vector(const bp::object& iterable) {
return std::vector<T>(bp::stl_input_iterator<T>(iterable),
bp::stl_input_iterator<T>());
}
void exposeSignals();
// Declare functions defined in other source files
namespace signalBase {
SignalBase<int>* createSignalWrapper(const char* name, const char* type,
bp::object object);
} // namespace signalBase
namespace entity {
/// \param obj an Entity object
void addCommands(boost::python::object obj);
void addSignals(boost::python::object obj);
Entity* create(const char* type, const char* name);
bp::object executeCmd(bp::tuple args, bp::dict);
} // namespace entity
namespace factory {
bp::tuple getEntityClassList();
}
namespace pool {
void writeGraph(const char* filename);
bp::list getEntityList();
const std::map<std::string, Entity*>* getEntityMap();
} // namespace pool
namespace debug {
void addLoggerFileOutputStream(const char* filename);
void addLoggerCoutOutputStream();
void closeLoggerFileOutputStream();
void realTimeLoggerSpinOnce();
void realTimeLoggerDestroy();
void realTimeLoggerInstance();
} // namespace debug
} // namespace python
} // namespace dynamicgraph
#endif
/*
* Copyright CNRS 2021
*
* Author: Florent Lamiraux
*
* This file is part of sot-core.
*/
#ifndef DYNAMIC_GRAPH_PYTHON_FWD_HH
#define DYNAMIC_GRAPH_PYTHON_FWD_HH
#include <dynamic-graph/fwd.hh>
namespace dynamicgraph {
namespace python {
class Interpreter;
typedef shared_ptr<Interpreter> InterpreterPtr_t;
} // namespace python
} // namespace dynamicgraph
#endif // DYNAMIC_GRAPH_PYTHON_FWD_HH
// -*- mode: c++ -*-
// Copyright 2011, Florent Lamiraux, CNRS.
#ifndef DYNAMIC_GRAPH_PYTHON_INTERPRETER_H
#define DYNAMIC_GRAPH_PYTHON_INTERPRETER_H
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <dynamic-graph/python/fwd.hh>
#include "dynamic-graph/python/api.hh"
#include "dynamic-graph/python/python-compat.hh"
namespace dynamicgraph {
namespace python {
///
/// This class implements a basis python interpreter.
///
/// String sent to method python are interpreted by an onboard python
/// interpreter.
class DYNAMIC_GRAPH_PYTHON_DLLAPI Interpreter {
public:
Interpreter();
~Interpreter();
/// \brief Method to start python interperter.
/// \param command string to execute
/// Method deprecated, you *SHOULD* handle error messages.
[[deprecated("you *SHOULD* handle error messages")]] std::string python(
const std::string& command);
/// \brief Method to start python interperter.
/// \param command string to execute, result, stdout, stderr strings
void python(const std::string& command, std::string& result, std::string& out,
std::string& err);
/// \brief Method to exectue a python script.
/// \param filename the filename
void runPythonFile(std::string filename);
void runPythonFile(std::string filename, std::string& err);
void runMain(void);
/// \brief Process input stream to send relevant blocks to python
/// \param stream input stream
std::string processStream(std::istream& stream, std::ostream& os);
/// \brief Return a pointer to the dictionary of global variables
PyObject* globals();
private:
/// The Python thread state
PyThreadState* _pyState;
/// Pointer to the dictionary of global variables
PyObject* globals_;
/// Pointer to the dictionary of local variables
PyObject* locals_;
PyObject* mainmod_;
};
} // namespace python
} // namespace dynamicgraph
#endif // DYNAMIC_GRAPH_PYTHON_INTERPRETER_H
#ifndef DYNAMIC_GRAPH_PYTHON_MODULE_HH
#define DYNAMIC_GRAPH_PYTHON_MODULE_HH
#ifdef PINOCCHIO_WITH_URDFDOM
// If pinocchio is used, we have to include pinocchio header before boost mpl
#include <pinocchio/fwd.hpp>
#endif
#include <dynamic-graph/entity.h>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/python.hpp>
#include <dynamic-graph/python/dynamic-graph-py.hh>
namespace dynamicgraph {
namespace python {
constexpr int AddSignals = 1;
constexpr int AddCommands = 2;
namespace internal {
template <typename T, int Options = AddCommands | AddSignals>
bp::object makeEntity1(const char* name) {
Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
assert(dynamic_cast<T*>(ent) != NULL);
bp::object obj(bp::ptr(static_cast<T*>(ent)));
if (Options & AddCommands) entity::addCommands(obj);
if (Options & AddSignals) entity::addSignals(obj);
return obj;
}
template <typename T, int Options = AddCommands | AddSignals>
bp::object makeEntity2() {
return makeEntity1<T, Options>("");
}
} // namespace internal
/// \tparam Options by default, all the signals and commands are added as
/// attribute to the Python object. This behaviour works fine for
/// entities that have static commands and signals.
/// If some commands or signals are added or removed dynamiccally, then
/// it is better to disable the default behaviour and handle it
/// specifically.
template <typename T,
typename bases = boost::python::bases<dynamicgraph::Entity>,
int Options = AddCommands | AddSignals>
inline auto exposeEntity() {
// std::string hiddenClassName ("_" + T::CLASS_NAME);
std::string hiddenClassName(T::CLASS_NAME);
namespace bp = boost::python;
bp::class_<T, bases, boost::noncopyable> obj(hiddenClassName.c_str(),
bp::init<std::string>());
/* TODO at the moment, I couldn't easily find a way to define a Python
constructor
* that would create the entity via the factory and then populate the
* python object with its commands.
* This is achieved with a factory function of the same name.
obj.def ("__init__", bp::raw_function(+[](bp::object args, bp::dict) {
if (bp::len(args) != 2)
throw std::length_error("Expected 2 arguments.");
bp::object self = args[0];
self.attr("__init__")(bp::extract<std::string>(args[1]));
Entity* ent = entity::create(T::CLASS_NAME.c_str(), name);
if (dynamic_cast<T*>(ent) == NULL)
std::cout << "foo" << std::endl;
assert(dynamic_cast<T*>(ent) != NULL);
self = bp::object(bp::ptr(static_cast<T*>(ent)));
//dynamicgraph::Entity& unused =
bp::extract<dynamicgraph::Entity&>(self);
//entity::addCommands(self);
})
;
*/
bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity1<T, Options>);
bp::def(T::CLASS_NAME.c_str(), &internal::makeEntity2<T, Options>);
if (!(Options & AddCommands)) obj.def("add_commands", &entity::addCommands);
if (!(Options & AddSignals)) obj.def("add_signals", &entity::addSignals);
return obj;
}
} // namespace python
} // namespace dynamicgraph
#endif // DYNAMIC_GRAPH_PYTHON_MODULE_HH
#ifndef DGPY_PYTHON_COMPAT_H
#define DGPY_PYTHON_COMPAT_H
#include <string>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
// Get any PyObject and get its str() representation as an std::string
std::string obj_to_str(PyObject* o);
#endif
// Copyright (c) 2018, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
#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 <boost/bind.hpp>
#include <boost/python.hpp>
#include "dynamic-graph/python/python-compat.hh"
namespace dynamicgraph {
namespace python {
class PythonSignalContainer : public Entity {
DYNAMIC_GRAPH_ENTITY_DECL();
public:
using Entity::Entity;
void signalRegistration(const SignalArray<int>& signals);
void rmSignal(const std::string& name);
};
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);
SignalWrapper(std::string name, pyobject callable)
: parent_t(name), callable(callable) {
typedef boost::function2<T&, T&, Time> function_t;
function_t f = boost::bind(&SignalWrapper::call, this, _1, _2);
this->setFunction(f);
}
virtual ~SignalWrapper(){};
private:
T& call(T& value, Time t) {
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
if (PyGILState_GetThisThreadState() == NULL) {
dgDEBUG(10) << "python thread not initialized" << std::endl;
}
pyobject obj = callable(t);
value = boost::python::extract<T>(obj);
PyGILState_Release(gstate);
return value;
}
pyobject callable;
};
} // namespace python
} // namespace dynamicgraph
#endif
// 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>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>
<!-- The following tag is recommended by REP-136 -->
<exec_depend condition="$ROS_VERSION == 1">catkin</exec_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>
<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
# Copyright 2010, 2011, Florent Lamiraux, Thomas Moulard, JRL, CNRS/AIST # Python bindings
#
# This file is part of dynamic-graph-python. add_subdirectory(dynamic_graph)
# dynamic-graph-python is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License set(PYTHON_SOURCES __init__.py attrpath.py entity.py signal_base.py
# as published by the Free Software Foundation, either version 3 of script_shortcuts.py tools.py)
# the License, or (at your option) any later version.
# foreach(source ${PYTHON_SOURCES})
# dynamic-graph-python is distributed in the hope that it will be useful, but python_install_on_site(dynamic_graph ${source})
# WITHOUT ANY WARRANTY; without even the implied warranty of endforeach(source)
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Lesser Public License for more details. You should have # --- ADD the wrap on the dg modules
# received a copy of the GNU Lesser General Public License along with link_directories(${DYNAMIC_GRAPH_PLUGINDIR})
# dynamic-graph-python. If not, see <http://www.gnu.org/licenses/>. dynamic_graph_python_module(
"tracer" dynamic-graph::tracer tracer-wrap SOURCE_PYTHON_MODULE
# ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/tracer/wrap.cc)
# Python dynamic_graph_python_module(
# "tracer_real_time" dynamic-graph::tracer-real-time tracer_real_time-wrap
INCLUDE(FindPythonLibs) SOURCE_PYTHON_MODULE
IF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) ${CMAKE_CURRENT_SOURCE_DIR}/dynamic_graph/tracer_real_time/wrap.cc)
MESSAGE(FATAL_ERROR "Python has not been found.")
ENDIF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE)
INCLUDE(FindPythonInterp)
IF (NOT ${PYTHONINTERP_FOUND} STREQUAL TRUE)
MESSAGE(FATAL_ERROR "Python executable has not been found.")
ENDIF (NOT ${PYTHONINTERP_FOUND} STREQUAL TRUE)
# provide path to library libdynamic-graph.so
LINK_DIRECTORIES(${DYNAMIC_GRAPH_LIBRARY_DIRS})
ADD_DEFINITIONS(${DYNAMIC_GRAPH_CFLAGS})
#
#
# Python bindings
#
#
SET(PYTHON_MODULE wrap)
ADD_LIBRARY(${PYTHON_MODULE}
MODULE
dynamic-graph-py.cc
signal-base-py.cc
entity-py.cc
factory-py.cc
signal-caster-py.cc
)
# Remove prefix lib
SET_TARGET_PROPERTIES(${PYTHON_MODULE}
PROPERTIES PREFIX "")
TARGET_LINK_LIBRARIES(${PYTHON_MODULE} ${DYNAMIC_GRAPH_LIBRARIES})
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
#
# Installation
#
EXEC_PROGRAM(${PYTHON_EXECUTABLE} ARGS "-c \"from distutils import sysconfig; print sysconfig.get_python_lib(0,0,prefix='')\""
OUTPUT_VARIABLE PYTHON_SITELIB)
MESSAGE(STATUS "PYTHON_SITELIB=${PYTHON_SITELIB}")
SET(PYTHON_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/${PYTHON_SITELIB}/dynamic_graph)
INSTALL(TARGETS ${PYTHON_MODULE}
DESTINATION
${PYTHON_INSTALL_DIR})
SET (PYTHON_SOURCES
dynamic_graph/__init__.py
dynamic_graph/entity.py
dynamic_graph/signal_base.py
)
SET (PYTHON_SOURCES_FULLPATH "")
FOREACH (SOURCE ${PYTHON_SOURCES})
SET(PYTHON_SOURCES_FULLPATH
${PYTHON_SOURCES_FULLPATH}
${CMAKE_SOURCE_DIR}/src/${SOURCE}
)
ENDFOREACH (SOURCE)
INSTALL(FILES ${PYTHON_SOURCES_FULLPATH}
DESTINATION ${PYTHON_INSTALL_DIR})
/*
* Copyright 2010 (C) CNRS
* Author: Florent Lamiraux
*/
#include <Python.h>
#include <iostream>
#include <sstream>
#include <string>
#include <dynamic-graph/debug.h>
#include <dynamic-graph/exception-factory.h>
#include <dynamic-graph/signal-base.h>
namespace dynamicgraph {
namespace python {
// Declare functions defined in other source files
namespace signalBase {
extern PyObject* create(PyObject* self, PyObject* args);
extern PyObject* getTime(PyObject* self, PyObject* args);
extern PyObject* getName(PyObject* self, PyObject* args);
extern PyObject* getValue(PyObject* self, PyObject* args);
extern PyObject* setValue(PyObject* self, PyObject* args);
extern PyObject* recompute(PyObject* self, PyObject* args);
}
namespace entity {
extern PyObject* create(PyObject* self, PyObject* args);
extern PyObject* getName(PyObject* self, PyObject* args);
extern PyObject* getSignal(PyObject* self, PyObject* args);
extern PyObject* displaySignals(PyObject* self, PyObject* args);
extern PyObject* executeCommand(PyObject* self, PyObject* args);
extern PyObject* listCommands(PyObject* self, PyObject* args);
extern PyObject* getCommandDocstring(PyObject* self, PyObject* args);
}
namespace factory {
PyObject* getEntityClassList(PyObject* self, PyObject* args);
}
namespace signalCaster {
PyObject* getSignalTypeList(PyObject* self, PyObject* args);
}
PyObject* error;
/**
\brief plug a signal into another one.
*/
PyObject*
plug(PyObject* self, PyObject* args)
{
PyObject* objOut = NULL;
PyObject* objIn = NULL;
void* pObjOut;
void* pObjIn;
if (!PyArg_ParseTuple(args,"OO", &objOut, &objIn))
return NULL;
if (!PyCObject_Check(objOut)) {
PyErr_SetString(PyExc_TypeError,
"first argument should be a pointer to"
" signalBase<int>.");
return NULL;
}
if (!PyCObject_Check(objIn)) {
PyErr_SetString(PyExc_TypeError,
"second argument should be a pointer to"
" signalBase<int>.");
return NULL;
}
pObjIn = PyCObject_AsVoidPtr(objIn);
SignalBase<int>* signalIn = (SignalBase<int>*)pObjIn;
pObjOut = PyCObject_AsVoidPtr(objOut);
SignalBase<int>* signalOut = (SignalBase<int>*)pObjOut;
std::ostringstream os;
try {
signalIn->plug(signalOut);
} catch (std::exception& exc) {
PyErr_SetString(error, exc.what());
return NULL;
}
return Py_BuildValue("");
}
PyObject*
enableTrace(PyObject* self, PyObject* args)
{
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 (boolean == Py_True) {
try {
DebugTrace::openFile(filename);
} catch (const std::exception& exc) {
PyErr_SetString(PyExc_IOError, exc.what());
return NULL;
}
} else {
try {
DebugTrace::closeFile(filename);
} catch (const std::exception& exc) {
PyErr_SetString(PyExc_IOError, exc.what());
return NULL;
}
}
} else {
return NULL;
}
return Py_BuildValue("");
}
}
}
/**
\brief List of python functions
*/
static PyMethodDef dynamicGraphMethods[] = {
{"w_plug", dynamicgraph::python::plug, METH_VARARGS,
"plug an output signal into an input signal"},
{"enableTrace", dynamicgraph::python::enableTrace, METH_VARARGS,
"Enable or disable tracing debug info in a file"},
// Signals
{"create_signal_base", dynamicgraph::python::signalBase::create, METH_VARARGS,
"create a SignalBase C++ object"},
{"signal_base_get_time", dynamicgraph::python::signalBase::getTime,
METH_VARARGS, "Get time of a SignalBase"},
{"signal_base_get_name", dynamicgraph::python::signalBase::getName,
METH_VARARGS, "Get the name of a signal"},
{"signal_base_get_value", dynamicgraph::python::signalBase::getValue,
METH_VARARGS, "Read the value of a signal"},
{"signal_base_set_value", dynamicgraph::python::signalBase::setValue,
METH_VARARGS, "Set the value of a signal"},
{"signal_base_recompute", dynamicgraph::python::signalBase::recompute,
METH_VARARGS, "Recompute the signal at given time"},
// Entity
{"create_entity", dynamicgraph::python::entity::create, METH_VARARGS,
"create an Entity C++ object"},
{"entity_get_name", dynamicgraph::python::entity::getName, METH_VARARGS,
"get the name of an Entity"},
{"entity_get_signal", dynamicgraph::python::entity::getSignal, METH_VARARGS,
"get signal by name from an Entity"},
{"entity_display_signals", dynamicgraph::python::entity::displaySignals,
METH_VARARGS,
"Display the list of signals of an entity in standard output"},
{"entity_execute_command",
dynamicgraph::python::entity::executeCommand,
METH_VARARGS,
"execute a command"},
{"entity_list_commands",
dynamicgraph::python::entity::listCommands,
METH_VARARGS,
"list the commands of an entity"},
{"entity_get_command_docstring",
dynamicgraph::python::entity::getCommandDocstring,
METH_VARARGS,
"get the docstring of an entity command"},
{"factory_get_entity_class_list",
dynamicgraph::python::factory::getEntityClassList,
METH_VARARGS,
"return the list of entity classes"},
{"signal_caster_get_type_list",
dynamicgraph::python::signalCaster::getSignalTypeList,
METH_VARARGS,
"return the list of signal type names"},
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyMODINIT_FUNC
initwrap(void)
{
PyObject *m;
m = Py_InitModule("wrap", dynamicGraphMethods);
if (m == NULL)
return;
std::string msg("dynamic_graph.error");
dynamicgraph::python::error =
PyErr_NewException(const_cast<char*>(msg.c_str()), NULL, NULL);
Py_INCREF(dynamicgraph::python::error);
PyModule_AddObject(m, "error", dynamicgraph::python::error);
}
# Copyright 2010-2021, Florent Lamiraux, Thomas Moulard, Olivier Stasse, Guilhem
# Saurel, JRL, CNRS/AIST, LAAS-CNRS
set(PYTHON_MODULE wrap)
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_link_libraries(${PYTHON_MODULE} PUBLIC ${PROJECT_NAME} eigenpy::eigenpy)
# Remove prefix lib
set_target_properties(${PYTHON_MODULE} PROPERTIES PREFIX "")
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)
...@@ -3,21 +3,8 @@ Copyright (c) 2010 CNRS ...@@ -3,21 +3,8 @@ Copyright (c) 2010 CNRS
Author: Florent Lamiraux Author: Florent Lamiraux
""" """
import sys, dl from __future__ import print_function
flags = sys.getdlopenflags()
# Import C++ symbols in a global scope
# This is necessary for signal compiled in different modules to be compatible
sys.setdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL)
from wrap import *
# Recover previous flags
sys.setdlopenflags(flags)
import entity, signal_base from . import entity # noqa
import re from . import signal_base # noqa
from .wrap import * # noqa
def plug (signalOut, signalIn) :
"""
Plug an output signal into an input signal
"""
# get signals and entities
w_plug(signalOut.obj, signalIn.obj)
# This module define the three functions:
# - getattrpath
# - setattrpath
# - existattrpath
# that work similarly as the get/setattr, but given path ("a.b.c.d")
# in input. Consider the following example:
# >>> setattrpath( e.__class__,"a.b.c.d",fun)
# with fun a function (self,*arg). Then, it is next possible to launch
# >>> e.a.b.c.d( ...)
# as if it was a classical member function of e.
from __future__ import print_function
class CommandPath(object):
"""
This class is only defined to implement a path of attribute
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"
if privateName in self.__dict__:
obj = getattr(self, privateName)
obj.mother = self.mother
return obj
return object.__getattr__(self, name)
def createCommandModule(target, name):
def createGetter(name):
def __(self):
obj = getattr(self, name)
obj.mother = self
return obj
return __
privateName = name + "_obj"
setattr(target, privateName, CommandPath())
if not isinstance(target, CommandPath):
setattr(target, name, property(createGetter(privateName)))
class CommandLauncher(object):
""" """
mother = None
fun = None
def __init__(self, fun):
self.fun = fun
def __call__(self, *arg):
return self.fun(self.mother, *arg)
def createCommandLauncher(target, name, fun):
if isinstance(target, CommandPath):
privateName = name + "_obj"
setattr(target, privateName, CommandLauncher(fun))
else:
setattr(target, name, fun)
def setattrpath(target, path, attribute):
"""
Create in target an new attribute with value path (available at
target.path1. ... .pathn).
"""
pathk = target
read = True
if isinstance(path, str):
path = path.split(".")
for tokenk in path[0:-1]:
if (not read) | (tokenk not in pathk.__dict__):
read = False
createCommandModule(pathk, tokenk)
pathk = getattr(pathk, tokenk + "_obj")
if callable(attribute):
createCommandLauncher(pathk, path[-1], attribute)
else:
print("Should not happen")
setattr(pathk, path[-1], attribute)
def getattrpath(target, path):
"""
Get in target the value located at path (available at
target.path1. ... .pathn).
"""
pathk = target
if isinstance(path, str):
path = path.split(".")
for tokenk in path:
privateName = tokenk + "_obj"
if hasattr(pathk, privateName):
pathk = getattr(pathk, privateName)
else:
if hasattr(pathk, tokenk):
pathk = getattr(pathk, tokenk)
else:
raise Exception(
'Path does not exist -- while accessing "'
+ tokenk
+ '" in '
+ ".".join(path)
)
return pathk
def existattrpath(target, path):
"""
Check for the existence in target of a value located at path (available at
target.path1. ... .pathn).
"""
pathk = target
if isinstance(path, str):
path = path.split(".")
for tokenk in path[0:-1]:
print("check ", tokenk)
privateName = tokenk + "_obj"
if privateName not in pathk.__dict__:
return False
pathk = getattr(pathk, privateName)
name = path[-1]
privateName = name + "_obj"
return (name in pathk.__dict__) | (privateName in pathk.__dict__)
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
#include "dynamic-graph/python/convert-dg-to-py.hh"
#include <dynamic-graph/signal-base.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/python-compat.hh"
namespace dynamicgraph {
using ::dynamicgraph::SignalBase;
namespace python {
namespace convert {
namespace bp = boost::python;
command::Value toValue(bp::object o, const command::Value::Type& valueType) {
using command::Value;
switch (valueType) {
case (Value::BOOL):
return Value(bp::extract<bool>(o));
case (Value::UNSIGNED):
return Value(bp::extract<unsigned>(o));
case (Value::INT):
return Value(bp::extract<int>(o));
case (Value::FLOAT):
return Value(bp::extract<float>(o));
case (Value::DOUBLE):
return Value(bp::extract<double>(o));
case (Value::STRING):
return Value(bp::extract<std::string>(o));
case (Value::VECTOR):
// TODO for backward compatibility, support tuple or list ?
// I don't think so
return Value(bp::extract<Vector>(o));
case (Value::MATRIX):
// TODO for backward compatibility, support tuple or list ?
// I don't think so
return Value(bp::extract<Matrix>(o));
case (Value::MATRIX4D):
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 std::invalid_argument(
"not implemented: cannot create a vector of values");
break;
default:
std::cerr << "Only int, double and string are supported." << std::endl;
}
return Value();
}
bp::object fromValue(const command::Value& value) {
using command::Value;
switch (value.type()) {
case (Value::BOOL):
return bp::object(value.boolValue());
case (Value::UNSIGNED):
return bp::object(value.unsignedValue());
case (Value::INT):
return bp::object(value.intValue());
case (Value::FLOAT):
return bp::object(value.floatValue());
case (Value::DOUBLE):
return bp::object(value.doubleValue());
case (Value::STRING):
return bp::object(value.stringValue());
case (Value::VECTOR):
return bp::object(value.vectorValue());
case (Value::MATRIX):
return bp::object(value.matrixXdValue());
case (Value::MATRIX4D):
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 bp::object();
}
}
} // namespace convert
} // namespace python
} // namespace dynamicgraph