From 1d505bed565d2a878eea2c2d5c8e0b9aca22068f Mon Sep 17 00:00:00 2001 From: Francois Keith <keith@lirmm.fr> Date: Tue, 18 Mar 2014 00:06:22 +0100 Subject: [PATCH] Add a method allowing to execute a file and retrived the error (if any) via a string. --- CMakeLists.txt | 1 + include/dynamic-graph/python/interpreter.hh | 1 + src/interpreter.cc | 64 ++++++++++++++++++++- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a32ff0a..ae34028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,7 @@ ADD_REQUIRED_DEPENDENCY("dynamic-graph >= 2.5.5-6") PKG_CONFIG_APPEND_LIBS("dynamic-graph-python") # Search for Boost. +SET(BOOST_COMPONENTS python filesystem system thread program_options unit_test_framework) SEARCH_FOR_BOOST() # Make sure Boost.Filesystem v2 is used. diff --git a/include/dynamic-graph/python/interpreter.hh b/include/dynamic-graph/python/interpreter.hh index 5addec4..5d2e4f3 100644 --- a/include/dynamic-graph/python/interpreter.hh +++ b/include/dynamic-graph/python/interpreter.hh @@ -51,6 +51,7 @@ namespace dynamicgraph { /// \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 diff --git a/src/interpreter.cc b/src/interpreter.cc index 9f1e2e5..0b97823 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -19,6 +19,13 @@ #include "dynamic-graph/python/interpreter.hh" #include "link-to-python.hh" +#include <boost/python/errors.hpp> +#include <boost/python/object.hpp> +#include <boost/python/handle.hpp> +#include <boost/python/extract.hpp> + +using namespace boost::python; + std::ofstream dg_debugfile( "/tmp/dynamic-graph-traces.txt", std::ios::trunc&std::ios::out ); // Python initialization commands @@ -136,6 +143,8 @@ Interpreter::Interpreter() PyRun_SimpleString(pythonPrefix[2].c_str()); PyRun_SimpleString(pythonPrefix[3].c_str()); PyRun_SimpleString(pythonPrefix[4].c_str()); + PyRun_SimpleString("import linecache"); + traceback_format_exception_ = PyDict_GetItemString (PyModule_GetDict(PyImport_AddModule("traceback")), "format_exception"); assert(PyCallable_Check(traceback_format_exception_)); @@ -229,13 +238,64 @@ PyObject* Interpreter::globals() void Interpreter::runPythonFile( std::string filename ) { + std::string err = ""; + runPythonFile(filename, err); +} + + +void Interpreter::runPythonFile( std::string filename, std::string& err) +{ + err = ""; PyObject* pymainContext = globals_; PyObject* run = PyRun_FileExFlags(fopen( filename.c_str(),"r" ), filename.c_str(), Py_file_input, pymainContext,pymainContext, true, NULL); if (PyErr_Occurred()) { - std::cout << "Error occures..." << std::endl; - PyErr_Print(); + PyObject *ptype, *pvalue, *ptraceback; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + + handle<> hTraceback(ptraceback); + object traceback(hTraceback); + + //Extract error message + std::string strErrorMessage = extract<std::string>(pvalue); + std::ostringstream errstream; + + //TODO does not work for now for a single command. + do + { + //Extract line number (top entry of call stack) + // if you want to extract another levels of call stack + // also process traceback.attr("tb_next") recurently + long lineno = extract<long> (traceback.attr("tb_lineno")); + std::string filename = extract<std::string> + (traceback.attr("tb_frame").attr("f_code").attr("co_filename")); + std::string funcname = extract<std::string> + (traceback.attr("tb_frame").attr("f_code").attr("co_name")); + errstream << " File \"" << filename <<"\", line " + << lineno << ", in "<< funcname << std::endl; + + // get the corresponding line. + std::ostringstream cmd; + cmd << "linecache.getline('"<<filename<<"', "<<lineno <<")"; + PyObject* line_obj = PyRun_String(cmd.str().c_str(), + Py_eval_input, globals_, globals_); + std::string line = PyString_AsString(line_obj); + Py_DecRef(line_obj); + + // remove the spaces at the beginning of the line. + size_t index = line.find_first_not_of (" \t"); + errstream << " " << line.substr(index, line.size()-index); + + // go to the next line. + traceback = traceback.attr("tb_next"); + } + while (traceback); + + // recreate the error message + errstream << strErrorMessage << std::endl; + err =errstream.str(); + std::cerr << err; } Py_DecRef(run); } -- GitLab