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 687 additions and 560 deletions
/*
* Copyright 2010,
* François Bleibel,
* Olivier Stasse,
*
* CNRS/AIST
*
* This file is part of dynamic-graph.
* dynamic-graph is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
* dynamic-graph is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. You should
* have received a copy of the GNU Lesser General Public License along
* with dynamic-graph. If not, see <http://www.gnu.org/licenses/>.
*/
#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 dynamicgraph
} // namespace python
/*
* Local variables:
* c-basic-offset: 2
* End:
*/
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
//
// This file is part of dynamic-graph-python.
// dynamic-graph-python is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// dynamic-graph-python is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Lesser Public License for more details. You should
// have received a copy of the GNU Lesser General Public License along
// with dynamic-graph. If not, see <http://www.gnu.org/licenses/>.
#include <Python.h>
#include <iostream>
#include <dynamic-graph/factory.h>
using dynamicgraph::Entity;
using dynamicgraph::ExceptionAbstract;
namespace dynamicgraph {
namespace python {
extern PyObject* error;
namespace factory {
/**
\brief Get name of entity
*/
PyObject* getEntityClassList(PyObject* /*self*/, PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
std::vector <std::string> classNames;
dynamicgraph::g_factory.listEntities(classNames);
unsigned int classNumber = classNames.size();
// Build a tuple object
PyObject* classTuple = PyTuple_New(classNumber);
for (unsigned int iEntity = 0; iEntity < classNames.size(); iEntity++) {
PyObject* className = Py_BuildValue("s", classNames[iEntity].c_str());
PyTuple_SetItem(classTuple, iEntity, className);
}
return Py_BuildValue("O", classTuple);
}
} // namespace factory
} // namespace python
} // namespace dynamicgraph
// -*- mode: c++ -*-
// Copyright 2011, Florent Lamiraux, CNRS.
//
// This file is part of dynamic-graph-python.
// dynamic-graph is free software: you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// dynamic-graph is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// dynamic-graph. If not, see <http://www.gnu.org/licenses/>.
#ifdef WIN32
#include <Windows.h>
#else
#include <dlfcn.h>
#endif
#include <iostream>
#include "dynamic-graph/debug.h"
#include "dynamic-graph/python/interpreter.hh"
std::ofstream dg_debugfile("/tmp/dynamic-graph-traces.txt",
std::ios::trunc& std::ios::out);
// Python initialization commands
namespace dynamicgraph {
namespace python {
static const std::string pythonPrefix[5] = {
"import sys\n",
"import traceback\n",
"if '' not in sys.path: sys.path.append('')\n",
"sys.argv = ['']\n",
"def display(s): return str(s) if not s is None else None"
};
namespace python {
static const std::string pythonPrefix[8] = {
"from __future__ import print_function\n",
"import traceback\n",
"class StdoutCatcher:\n"
" def __init__(self):\n"
" self.data = ''\n"
" def write(self, stuff):\n"
" self.data = self.data + stuff\n"
" def fetch(self):\n"
" s = self.data[:]\n"
" self.data = ''\n"
" return s\n",
"stdout_catcher = StdoutCatcher()\n",
"stderr_catcher = StdoutCatcher()\n",
"import sys\n",
"sys.stdout = stdout_catcher",
"sys.stderr = stderr_catcher"};
bool HandleErr(std::string& err, PyObject* globals_, int PythonInputType) {
dgDEBUGIN(15);
err = "";
bool lres = false;
if (PyErr_Occurred() != NULL) {
bool is_syntax_error = PyErr_ExceptionMatches(PyExc_SyntaxError);
PyErr_Print();
PyObject* stderr_obj = PyRun_String("stderr_catcher.fetch()", Py_eval_input,
globals_, globals_);
err = obj_to_str(stderr_obj);
Py_DECREF(stderr_obj);
// Here if there is a syntax error and
// and the interpreter input is set to Py_eval_input,
// it is maybe a statement instead of an expression.
// Therefore we indicate to re-evaluate the command.
if (is_syntax_error && PythonInputType == Py_eval_input) {
dgDEBUG(15) << "Detected a syntax error " << std::endl;
lres = false;
} else
lres = true;
PyErr_Clear();
} else {
dgDEBUG(15) << "no object generated but no error occured." << std::endl;
}
return lres;
}
using dynamicgraph::python::Interpreter;
Interpreter::Interpreter()
{
Interpreter::Interpreter() {
// load python dynamic library
// this is silly, but required to be able to import dl module.
#ifndef WIN32
dlopen(PYTHON_LIBRARY, RTLD_LAZY | RTLD_GLOBAL);
#endif
Py_Initialize();
#if PY_MAJOR_VERSION < 3 || PY_MINOR_VERSION < 7
PyEval_InitThreads();
#endif
mainmod_ = PyImport_AddModule("__main__");
Py_INCREF(mainmod_);
globals_ = PyModule_GetDict(mainmod_);
......@@ -45,73 +86,168 @@ Interpreter::Interpreter()
PyRun_SimpleString(pythonPrefix[2].c_str());
PyRun_SimpleString(pythonPrefix[3].c_str());
PyRun_SimpleString(pythonPrefix[4].c_str());
traceback_format_exception_ = PyDict_GetItemString
(PyModule_GetDict(PyImport_AddModule("traceback")), "format_exception");
assert(PyCallable_Check(traceback_format_exception_));
Py_INCREF(traceback_format_exception_);
}
PyRun_SimpleString(pythonPrefix[5].c_str());
PyRun_SimpleString(pythonPrefix[6].c_str());
PyRun_SimpleString(pythonPrefix[7].c_str());
PyRun_SimpleString("import linecache");
Interpreter::~Interpreter()
{
//Py_DECREF(mainmod_);
//Py_DECREF(globals_);
//Py_DECREF(traceback_format_exception_);
Py_Finalize();
// Allow threads
_pyState = PyEval_SaveThread();
}
std::string Interpreter::python( const std::string& command )
{
PyObject* result = PyRun_String(command.c_str(), Py_eval_input, globals_,
globals_);
if (!result) {
PyErr_Clear();
result = PyRun_String(command.c_str(), Py_single_input, globals_,
globals_);
}
if (result == NULL) {
if (PyErr_Occurred()) {
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
if (ptraceback == NULL) {
ptraceback = Py_None;
}
PyObject* args = PyTuple_New(3);
PyTuple_SET_ITEM(args, 0, ptype);
PyTuple_SET_ITEM(args, 1, pvalue);
PyTuple_SET_ITEM(args, 2, ptraceback);
result = PyObject_CallObject(traceback_format_exception_, args);
assert(PyList_Check(result));
unsigned int size = PyList_GET_SIZE(result);
std::string stringRes;
for (unsigned int i=0; i<size; i++) {
stringRes += std::string(PyString_AsString(PyList_GET_ITEM(result, i)));
Interpreter::~Interpreter() {
PyEval_RestoreThread(_pyState);
// Ideally, we should call Py_Finalize but this is not really supported by
// Python.
// Instead, we merelly remove variables.
// Code was taken here:
// https://github.com/numpy/numpy/issues/8097#issuecomment-356683953
{
PyObject* poAttrList = PyObject_Dir(mainmod_);
PyObject* poAttrIter = PyObject_GetIter(poAttrList);
PyObject* poAttrName;
while ((poAttrName = PyIter_Next(poAttrIter)) != NULL) {
std::string oAttrName(obj_to_str(poAttrName));
// Make sure we don't delete any private objects.
if (oAttrName.compare(0, 2, "__") != 0 ||
oAttrName.compare(oAttrName.size() - 2, 2, "__") != 0) {
PyObject* poAttr = PyObject_GetAttr(mainmod_, poAttrName);
// Make sure we don't delete any module objects.
if (poAttr && poAttr->ob_type != mainmod_->ob_type)
PyObject_SetAttr(mainmod_, poAttrName, NULL);
Py_DECREF(poAttr);
}
result = PyString_FromString(stringRes.c_str());
PyErr_Clear();
} else {
std::cout << "Result is NULL but no error occurred." << std::endl;
Py_DECREF(poAttrName);
}
Py_DECREF(poAttrIter);
Py_DECREF(poAttrList);
}
Py_DECREF(mainmod_);
Py_DECREF(globals_);
// Py_Finalize();
}
std::string Interpreter::python(const std::string& command) {
std::string lerr(""), lout(""), lres("");
python(command, lres, lout, lerr);
return lres;
}
void Interpreter::python(const std::string& command, std::string& res,
std::string& out, std::string& err) {
res = "";
out = "";
err = "";
// Check if the command is not a python comment or empty.
std::string::size_type iFirstNonWhite = command.find_first_not_of(" \t");
// Empty command
if (iFirstNonWhite == std::string::npos) return;
// Command is a comment. Ignore it.
if (command[iFirstNonWhite] == '#') return;
PyEval_RestoreThread(_pyState);
std::cout << command.c_str() << std::endl;
PyObject* result =
PyRun_String(command.c_str(), Py_eval_input, globals_, globals_);
// Check if the result is null.
if (result == NULL) {
// Test if this is a syntax error (due to the evaluation of an expression)
// else just output the problem.
if (!HandleErr(err, globals_, Py_eval_input)) {
// If this is a statement, re-parse the command.
result =
PyRun_String(command.c_str(), Py_single_input, globals_, globals_);
// If there is still an error build the appropriate err string.
if (result == NULL) HandleErr(err, globals_, Py_single_input);
// If there is no error, make sure that the previous error message is
// erased.
else
err = "";
} else
dgDEBUG(15) << "Do not try a second time." << std::endl;
}
PyObject* stdout_obj = 0;
stdout_obj =
PyRun_String("stdout_catcher.fetch()", Py_eval_input, globals_, globals_);
out = obj_to_str(stdout_obj);
Py_DECREF(stdout_obj);
// Local display for the robot (in debug mode or for the logs)
if (out.size() != 0) std::cout << "Output:" << out << std::endl;
if (err.size() != 0) std::cout << "Error:" << err << std::endl;
// If python cannot build a string representation of result
// then results is equal to NULL. This will trigger a SEGV
dgDEBUG(15) << "For command: " << command << std::endl;
if (result != NULL) {
res = obj_to_str(result);
dgDEBUG(15) << "Result is: " << res << std::endl;
Py_DECREF(result);
} else {
result = PyObject_Str(result);
dgDEBUG(15) << "Result is: empty" << std::endl;
}
std::string value = PyString_AsString(result);
return value;
dgDEBUG(15) << "Out is: " << out << std::endl;
dgDEBUG(15) << "Err is :" << err << std::endl;
_pyState = PyEval_SaveThread();
return;
}
void Interpreter::runPythonFile( std::string filename )
{
Py_Finalize();
Py_Initialize();
PyRun_SimpleString(pythonPrefix[0].c_str());
PyRun_SimpleString(pythonPrefix[1].c_str());
PyRun_SimpleString(pythonPrefix[2].c_str());
PyRun_SimpleString(pythonPrefix[4].c_str());
PyRun_SimpleFile(NULL, filename.c_str());
PyObject* Interpreter::globals() { return globals_; }
void Interpreter::runPythonFile(std::string filename) {
std::string err = "";
runPythonFile(filename, err);
}
void Interpreter::runPythonFile(std::string filename, std::string& err) {
FILE* pFile = fopen(filename.c_str(), "r");
if (pFile == 0x0) {
err = filename + " cannot be open";
return;
}
PyEval_RestoreThread(_pyState);
err = "";
PyObject* run =
PyRun_File(pFile, filename.c_str(), Py_file_input, globals_, globals_);
if (run == NULL) {
HandleErr(err, globals_, Py_file_input);
std::cerr << err << std::endl;
}
Py_DecRef(run);
_pyState = PyEval_SaveThread();
fclose(pFile);
}
std::string Interpreter::processStream(std::istream& stream, std::ostream& os)
{
char line[10000]; sprintf(line, "%s", "\n");
void Interpreter::runMain(void) {
PyEval_RestoreThread(_pyState);
#if PY_MAJOR_VERSION >= 3
const Py_UNICODE* argv[] = {L"dg-embedded-pysh"};
Py_Main(1, const_cast<Py_UNICODE**>(argv));
#else
const char* argv[] = {"dg-embedded-pysh"};
Py_Main(1, const_cast<char**>(argv));
#endif
_pyState = PyEval_SaveThread();
}
std::string Interpreter::processStream(std::istream& stream, std::ostream& os) {
char line[10000];
sprintf(line, "%s", "\n");
std::string command;
std::streamsize maxSize = 10000;
#if 0
......@@ -126,3 +262,6 @@ std::string Interpreter::processStream(std::istream& stream, std::ostream& os)
#endif
return command;
}
} // namespace python
} // namespace dynamicgraph
This diff is collapsed.
// Copyright 2010, Florent Lamiraux, Thomas Moulard, LAAS-CNRS.
//
// This file is part of dynamic-graph-python.
// dynamic-graph-python is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// dynamic-graph-python is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Lesser Public License for more details. You should
// have received a copy of the GNU Lesser General Public License along
// with dynamic-graph. If not, see <http://www.gnu.org/licenses/>.
#include <Python.h>
#include <iostream>
#include <sstream>
#include <dynamic-graph/signal-caster.h>
namespace dynamicgraph {
namespace python {
extern PyObject* error;
namespace signalCaster {
PyObject* getSignalTypeList(PyObject* /*self*/, PyObject* args)
{
if (!PyArg_ParseTuple(args, ""))
return NULL;
std::vector<std::string> typeList =
dynamicgraph::g_caster().listTypenames();
unsigned int typeNumber = typeList.size();
// Build a tuple object
PyObject* typeTuple = PyTuple_New(typeNumber);
for (unsigned int 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 dynamicgraph
} // namespace python
# Copyright 2010-2020, Florent Lamiraux, Thomas Moulard, Olivier Stasse, Guilhem
# Saurel, JRL, CNRS/AIST, LAAS-CNRS
# Test the interpreter
add_unit_test(interpreter-test interpreter-test.cc)
target_link_libraries(interpreter-test PRIVATE ${PROJECT_NAME})
# Test runfile
add_unit_test(interpreter-test-runfile interpreter-test-runfile.cc)
target_link_libraries(interpreter-test-runfile PRIVATE ${PROJECT_NAME})
target_include_directories(interpreter-test-runfile
PRIVATE Boost::unit_test_framework)
target_compile_definitions(interpreter-test-runfile
PRIVATE PATH="${CMAKE_CURRENT_LIST_DIR}/")
# Test the module generation Create an entity
set(LIBRARY_NAME "custom_entity")
add_library(${LIBRARY_NAME} SHARED "${LIBRARY_NAME}.cpp")
if(SUFFIX_SO_VERSION)
set_target_properties(${LIBRARY_NAME} PROPERTIES SOVERSION ${PROJECT_VERSION})
endif(SUFFIX_SO_VERSION)
target_link_libraries(${LIBRARY_NAME} PRIVATE dynamic-graph::dynamic-graph)
# Create its bindings This mimics DYNAMIC_GRAPH_PYTHON_MODULE(${LIBRARY_NAME}
# ${LIBRARY_NAME} "${LIBRARY_NAME}-wrap")
configure_file(
${PROJECT_SOURCE_DIR}/cmake/dynamic_graph/submodule/__init__.py.cmake
${CMAKE_CURRENT_BINARY_DIR}/${LIBRARY_NAME}/__init__.py)
set(PYTHON_MODULE "${LIBRARY_NAME}-wrap")
set(DYNAMICGRAPH_MODULE_HEADER
"${CMAKE_SOURCE_DIR}/tests/custom_entity_module.h")
configure_file(${PROJECT_SOURCE_DIR}/cmake/dynamic_graph/python-module-py.cc.in
${CMAKE_CURRENT_BINARY_DIR}/python-module-py.cc @ONLY)
add_library(${PYTHON_MODULE} MODULE
${CMAKE_CURRENT_BINARY_DIR}/python-module-py.cc)
set_target_properties(${PYTHON_MODULE}
PROPERTIES PREFIX "" OUTPUT_NAME ${LIBRARY_NAME}/wrap)
if(UNIX AND NOT APPLE)
target_link_libraries(${PYTHON_MODULE} PRIVATE "-Wl,--no-as-needed")
endif(UNIX AND NOT APPLE)
target_link_libraries(${PYTHON_MODULE} PRIVATE ${LIBRARY_NAME} ${PROJECT_NAME})
# Test it
add_python_unit_test("test-custom-entity" "tests/test_custom_entity.py" src
tests)
# also test other bindings, using this custom entity
add_python_unit_test("test-bindings" "tests/test_bindings.py" src tests)
This diff is collapsed.
This diff is collapsed.
#include "custom_entity.h"
typedef boost::mpl::vector<dynamicgraph::CustomEntity> entities_t;
......@@ -2,10 +2,10 @@
* Copyright
*/
#include "dynamic-graph-python-test.hh"
#include <iostream>
#include "dynamic-graph-python-test.hh"
GraphTest::GraphTest()
{
GraphTest::GraphTest() {
std::cout << "Constructor of unitTesting object of class Graph." << std::endl;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.