From fe0a6faf9747d3619223ccef261affec3a5c83ac Mon Sep 17 00:00:00 2001 From: Olivier Stasse <olivier.stasse@gmail.com> Date: Mon, 23 Jul 2012 17:25:03 +0200 Subject: [PATCH] Add test to detect statement in evaluation. This commit detect when a statement is evaluated with PyRun_String run with Py_eval_input. This seems to generate a Syntax Error. Thus if an exception with Syntax Error is generated with Py_eval_input, the python interpreter does a second pass with Py_single_input. The string err is set appropriatly, out has to be checked. --- src/interpreter.cc | 161 ++++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 67 deletions(-) diff --git a/src/interpreter.cc b/src/interpreter.cc index a0cd181..38ac726 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -43,6 +43,66 @@ namespace dynamicgraph { using dynamicgraph::python::Interpreter; using dynamicgraph::python::libpython; +bool HandleErr(std::string & err, + PyObject * traceback_format_exception, + PyObject * globals_, + int PythonInputType) +{ + err=""; + bool lres=false; + + if (PyErr_Occurred()) { + std::cout << "v3.0 An exception was raised in the python interpreter." << std::endl; + PyObject *ptype, *pvalue, *ptraceback, *pyerr; + 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); + pyerr = PyObject_CallObject(traceback_format_exception, args); + assert(PyList_Check(pyerr)); + unsigned int size = PyList_GET_SIZE(pyerr); + std::string stringRes; + for (unsigned int i=0; i<size; i++) { + stringRes += std::string(PyString_AsString(PyList_GET_ITEM(pyerr, i))); + } + pyerr = PyString_FromString(stringRes.c_str()); + err = PyString_AsString(pyerr); + std::cout << "err: " << err << std::endl; + + // 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 (PyErr_GivenExceptionMatches(ptype, PyExc_SyntaxError) && + (PythonInputType==Py_eval_input)) + { + std::cout << "Detected a syntax error " << std::endl; + lres=false; + } + else + lres=true; + + PyErr_Clear(); + } else { + std::cout << "no object generated but no error occured." << std::endl; + } + PyObject* stdout_obj = PyRun_String("stdout_catcher.fetch()", + Py_eval_input, globals_, + globals_); + std::string out(""); + + out = PyString_AsString(stdout_obj); + // Local display for the robot (in debug mode or for the logs) + if (out.length()!=0) + std::cout << out; + else std::cout << "No exception." << std::endl; + return lres; +} + Interpreter::Interpreter() { // load python dynamic library @@ -77,86 +137,45 @@ Interpreter::~Interpreter() 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))); - } - result = PyString_FromString(stringRes.c_str()); - PyErr_Clear(); - } else { - std::cout << "Result is NULL but no error occurred." << std::endl; - } - } else { - result = PyObject_Repr(result); - } - std::string value = ""; - // PyString_AsString will generate a segv if result is NULL. - // This might be the case if PyObject_Repr fails. - if (result!=NULL) - value = PyString_AsString(result); - return value; + 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 = ""; + PyObject* result = PyRun_String(command.c_str(), Py_eval_input, globals_, globals_); + // Check if the result is null. 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; - 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); - pyerr = PyObject_CallObject(traceback_format_exception_, args); - assert(PyList_Check(pyerr)); - unsigned int size = PyList_GET_SIZE(pyerr); - std::string stringRes; - for (unsigned int i=0; i<size; i++) { - stringRes += std::string(PyString_AsString(PyList_GET_ITEM(pyerr, i))); + // Test if this is a syntax error (due to the evaluation of an expression) + // else just output the problem. + if (!HandleErr(err, + traceback_format_exception_, 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, + traceback_format_exception_, globals_, + Py_single_input); + else + // If there is no error, make sure that the previous error message is erased. + err=""; } - pyerr = PyString_FromString(stringRes.c_str()); - err = PyString_AsString(pyerr); - PyErr_Clear(); - } else { - std::cout << "Result is NULL but no error occurred." << std::endl; - } + else std::cout << "Do not try a second time." << std::endl; } + PyObject* stdout_obj = PyRun_String("stdout_catcher.fetch()", Py_eval_input, globals_, globals_); @@ -167,7 +186,15 @@ void Interpreter::python( const std::string& command, std::string& res, // If python cannot build a string representation of result // then results is equal to NULL. This will trigger a SEGV if (result!=NULL) - res = PyString_AsString(result); + { + std::cout << "For command :" << command << std::endl; + res = PyString_AsString(result); + std::cout << "Result is: " << res <<std::endl; + std::cout << "Out is: " << out <<std::endl; + std::cout << "Err is :" << err << std::endl; + } + else + std::cout << "Result is empty" << std::endl; return; } -- GitLab