From 8fca0b1a7053beeb48eac0287ae2d62f0261bc87 Mon Sep 17 00:00:00 2001 From: florent <florent@laas.fr> Date: Mon, 10 Jan 2011 15:48:33 +0100 Subject: [PATCH] Add method to interprete a string as a python command in class Interpreter. * include/dynamic-graph/interpreter.h, * src/CMakeLists.txt, * src/dgraph/interpreter.cpp, * tests/CMakeLists.txt, * tools/dg-python.cpp: new, * tools/CMakeLists.txt: this adds a dependency to python in dynamic-graph. --- include/dynamic-graph/interpreter.h | 17 +++- src/CMakeLists.txt | 19 ++++ src/dgraph/interpreter.cpp | 57 ++++++++++- tests/CMakeLists.txt | 11 +++ tools/CMakeLists.txt | 14 ++- tools/dg-python.cpp | 140 ++++++++++++++++++++++++++++ 6 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 tools/dg-python.cpp diff --git a/include/dynamic-graph/interpreter.h b/include/dynamic-graph/interpreter.h index 95866c0..7d07543 100644 --- a/include/dynamic-graph/interpreter.h +++ b/include/dynamic-graph/interpreter.h @@ -168,7 +168,22 @@ namespace dynamicgraph \par[in] prompt: The prompt to be displayed. */ - void shell( std::istream& sin, std::ostream& sout, const std::string& prompt="" ); + void shell( std::istream& sin, std::ostream& sout, + const std::string& prompt=""); + /*! \brief Method to start python interperter. + \par[in] sin: The input stream from which the command will be extracted. + \par[out] sout: The output stream to which the result will be displayed. + \par[in] prompt: The prompt to be displayed. + + */ + void python( std::istream& sin, std::ostream& sout, + const std::string& prompt="" ); + + /*! \brief Method to exectue a python script. + \par[in] sin: The filename + */ + void runPythonFile( std::string filename ); + void writeCompletionList(std::ostream& os); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5554891..c211f47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -93,3 +93,22 @@ FOREACH(plugin_file ${plugins_list}) INSTALL(TARGETS ${plugin} DESTINATION ${PLUGINDIR}) ENDFOREACH(plugin_file) + +# +# Python +# +INCLUDE(FindPythonLibs) +IF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + 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}) + +INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) diff --git a/src/dgraph/interpreter.cpp b/src/dgraph/interpreter.cpp index 64a7ee0..1cf1a09 100644 --- a/src/dgraph/interpreter.cpp +++ b/src/dgraph/interpreter.cpp @@ -22,6 +22,9 @@ /* --- INCLUDE --------------------------------------------------------- */ /* --------------------------------------------------------------------- */ +/* PYTHON */ +#include <Python.h> + #include <boost/format.hpp> /* DYNAMIC-GRAPH */ @@ -38,7 +41,13 @@ using namespace dynamicgraph; /* --- CLASS ----------------------------------------------------------- */ /* --------------------------------------------------------------------- */ -const std::string Interpreter::PROMPT_DEFAULT = "> "; +namespace dynamicgraph { + const std::string Interpreter::PROMPT_DEFAULT = "> "; + static const std::string pythonPrefix[2] = { + "import sys", + "if '' not in sys.path: sys.path.append('')" + }; +} Interpreter:: Interpreter( PluginLoader* dl__ ) @@ -503,6 +512,52 @@ shell( std::istream& sin, std::ostream& sout, const std::string& promptUser ) } } +void Interpreter:: +python( std::istream& sin, std::ostream& sout, const std::string& promptUser ) +{ + Py_Initialize(); + PyRun_SimpleString(pythonPrefix[0].c_str()); + PyRun_SimpleString(pythonPrefix[1].c_str()); + while( 1 ) + { + if( promptUser.length() ) sout << promptUser; else sout << prompt; + const int SIZE = 16384; + char pythonLine[SIZE]; + if( sin.eof() ) break; + + sin.getline( pythonLine,SIZE-1 ); + + if( sin.gcount () >= SIZE-2 ) + { + sout << "!! Line size exceeded" << endl; + do{ + sin.getline( pythonLine,SIZE-1 ); + } + while ( sin.gcount () >= SIZE-2 ); + } + else + { + try{ + PyRun_SimpleString(pythonLine); + } + catch( exception& e ) { dgDEBUG(1) << e.what(); throw; } + catch(...) { dgDEBUG(1) << "!! unknow!." <<endl; throw; } + } + } + Py_Finalize(); + sout << std::endl; +} + +void Interpreter:: +runPythonFile( std::string filename ) +{ + Py_Initialize(); + PyRun_SimpleString(pythonPrefix[0].c_str()); + PyRun_SimpleString(pythonPrefix[1].c_str()); + PyRun_SimpleFile(NULL, filename.c_str()); + Py_Finalize(); +} + ShellFunctionRegisterer:: ShellFunctionRegisterer( const std::string& funName, const Interpreter::ShellBasicFunction& f) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d6dc7a1..862998d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -15,6 +15,16 @@ ADD_DEFINITIONS(-DDEBUG=2) +# +# Python +# +INCLUDE(FindPythonLibs) +IF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + MESSAGE(FATAL_ERROR "Python has not been found.") +ELSE (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + MESSAGE(STATUS "PYTHON_LIBRARY="${PYTHON_LIBRARY}) +ENDIF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + # Add Boost path to include directories. INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) @@ -37,6 +47,7 @@ MACRO(DYNAMIC_GRAPH_TEST NAME) ADD_TEST(${NAME} ${RUNTIME_OUTPUT_DIRECTORY}/${NAME}) TARGET_LINK_LIBRARIES(${NAME} ${PROJECT_NAME}) + TARGET_LINK_LIBRARIES(${NAME} ${PYTHON_LIBRARY}) ADD_DEPENDENCIES(${NAME} ${PROJECT_NAME}) # Link against Boost. diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5c7f989..f930695 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -13,7 +13,17 @@ # received a copy of the GNU Lesser General Public License along with # dynamic-graph. If not, see <http://www.gnu.org/licenses/>. -SET(tools dg-shell) +SET(tools dg-shell dg-python) + +# +# Python +# +INCLUDE(FindPythonLibs) +IF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + MESSAGE(FATAL_ERROR "Python has not been found.") +ELSE (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) + MESSAGE(STATUS "PYTHON_LIBRARY="${PYTHON_LIBRARY}) +ENDIF (NOT ${PYTHONLIBS_FOUND} STREQUAL TRUE) include_directories(${Boost_INCLUDE_DIRS}) @@ -38,12 +48,14 @@ FOREACH(tool_name ${tools}) INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${PYTHON_INCLUDE_PATH} ) LINK_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/lib) TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} ${PROJECT_NAME}) + TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} ${PYTHON_LIBRARY}) IF(UNIX) TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} dl) diff --git a/tools/dg-python.cpp b/tools/dg-python.cpp new file mode 100644 index 0000000..c6fccd9 --- /dev/null +++ b/tools/dg-python.cpp @@ -0,0 +1,140 @@ +// Copyright 2010, François Bleibel, Thomas Moulard, Olivier Stasse, +// JRL, 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 +// 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 <sstream> +#include <string> +#include <vector> + +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/program_options.hpp> + +#include <dynamic-graph/entity.h> +#include <dynamic-graph/plugin-loader.h> +#include <dynamic-graph/interpreter.h> +#include <dynamic-graph/debug.h> + +extern std::ofstream debugfile; + +// Factorize exception catching code. +#define CATCH_EXCEPTIONS() \ + catch (std::exception& e) \ + { \ + std::cout \ + << errorPrefix \ + << e.what () << std::endl; \ + } \ + catch (const char* str) \ + { \ + std::cout << errorPrefix \ + << "Unknown exception " << str << std::endl; \ + } \ + catch (...) \ + { \ + dgDEBUG(5) << errorPrefix << " Unknown exception " << std::endl; \ + } \ + struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n + +struct Options +{ + /// \brief Prologue path (a prologue is a script implicitly + /// evaluated at start-up). + std::string prologue; + /// \brief Files to be evaluated at start-up (left to right order). + std::vector<std::string> inputs; +}; + +int main (int argc, char** argv) +{ + dgDEBUGIN(15); + + dgDEBUG(5) << " Loading..." << std::endl; + Options options; + + // Parse options. + namespace po = boost::program_options; + po::options_description desc ("Allowed options"); + desc.add_options () + ("input,i", + po::value<std::vector<std::string> >(&options.inputs), + "file(s) evaluated at start-up") + ("help,h", "produce help message") + ; + + po::positional_options_description p; + p.add("input", -1); + + po::variables_map vm; + + try + { + po::store(po::command_line_parser(argc, argv). + options(desc).positional(p).run(), vm); + po::notify(vm); + + if (vm.count ("help")) + { + std::cout << "Usage: " << argv[0] << " [options]" << std::endl + << desc << std::endl + << "Report bugs to <hpp@laas.fr>" << std::endl; + return 1; + } + } + catch (po::error& error) + { + std::cerr << "Error while parsing argument: " + << error.what () << std::endl; + return 1; + } + + std::list<std::string> inputs (options.inputs.begin (), + options.inputs.end ()); + + // Load all input files. + BOOST_FOREACH (const std::string& pathStr, inputs) + { + boost::filesystem::path path (pathStr); + + std::stringstream ss; + ss << "!! In file <" << path.file_string () << "> : "; + std::string errorPrefix = ss.str (); + + try + { + dynamicgraph::g_shell.runPythonFile (path.file_string ()); + } + CATCH_EXCEPTIONS (); + return 0; + } + + std::string errorPrefix = ""; + while (1) + { + try + { + dgDEBUG(5) << "Run shell." << std::endl; + dynamicgraph::g_shell.python (std::cin, std::cout, ">>> "); + dgDEBUG(5) << "Shell over." << std::endl; + if (std::cin.eof ()) + break; + } + CATCH_EXCEPTIONS (); + } + + dgDEBUGOUT(15); + return 0; +} -- GitLab