From 681a9955357ddf2cbc1d21b89191d0c70b2f1845 Mon Sep 17 00:00:00 2001 From: Peter Peterson Date: Wed, 8 Jan 2014 14:41:00 -0500 Subject: [PATCH] Re #8686. Added real filename and line number when emitting errors. Required a small refactor of the code. Hopefully the additional comments help out. --- Code/Mantid/MantidPlot/src/PythonScript.cpp | 55 ++++++++++++++------- Code/Mantid/MantidPlot/src/PythonScript.h | 5 +- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/Code/Mantid/MantidPlot/src/PythonScript.cpp b/Code/Mantid/MantidPlot/src/PythonScript.cpp index fefc79fa03a1..8e6daebfd072 100644 --- a/Code/Mantid/MantidPlot/src/PythonScript.cpp +++ b/Code/Mantid/MantidPlot/src/PythonScript.cpp @@ -223,27 +223,43 @@ void PythonScript::generateAutoCompleteList() } /** - * Convert a python error state into a human-readable string - * - * @return A string containing the error message + * This emits the error signal and resets the error state + * of the python interpreter. */ -QString PythonScript::constructErrorMsg() +void PythonScript::emit_error() { + // gil is necessary so other things don't continue GlobalInterpreterLock gil; - QString message; - if (!PyErr_Occurred()) - { - return message; - } + + // return early if nothing happened + if (!PyErr_Occurred()) + return; + + // get the error information out PyObject *exception(NULL), *value(NULL), *traceback(NULL); PyErr_Fetch(&exception, &value, &traceback); + + // prework on the exception handling PyErr_NormalizeException(&exception, &value, &traceback); PyErr_Clear(); + + // convert the traceback into something useful + int lineNumber = 0; + QString filename; + if (traceback) + { + PyTracebackObject* tb = (PyTracebackObject*)traceback; + lineNumber = tb->tb_lineno; + filename = PyString_AsString(tb->tb_frame->f_code->co_filename); + } + + // the error message is the full (formated) traceback PyObject *str_repr = PyObject_Str(value); + QString message; QTextStream msgStream(&message); if( value && str_repr ) { - if(exception == PyExc_SyntaxError) + if(exception == PyExc_SyntaxError) { msgStream << constructSyntaxErrorStr(value); } @@ -253,7 +269,7 @@ QString PythonScript::constructErrorMsg() excTypeName = excTypeName.section(".", -1); msgStream << excTypeName << ": " << PyString_AsString(str_repr); } - + } else { @@ -265,7 +281,8 @@ QString PythonScript::constructErrorMsg() Py_XDECREF(traceback); Py_XDECREF(exception); Py_XDECREF(value); - return msgStream.readAll(); + + emit error(msgStream.readAll(), filename, lineNumber); } /** @@ -468,7 +485,7 @@ QVariant PythonScript::evaluateImpl() } else { - emit error(constructErrorMsg(), "", 0); + emit_error(); return QVariant(); } } @@ -538,7 +555,7 @@ QVariant PythonScript::evaluateImpl() } else { - emit error(constructErrorMsg(), "", 0); + emit_error(); } return QVariant(); } @@ -567,13 +584,14 @@ bool PythonScript::executeString() // If an error has occurred we need to construct the error message // before any other python code is run QString msg; - if(!result) + if(!result) { - msg = constructErrorMsg(); // Also clears error indicator + emit_error(); } else { - msg = "Script execution finished."; + QString msg = "Script execution finished."; + emit finished(msg); success = true; } if(isInteractive()) @@ -583,8 +601,7 @@ bool PythonScript::executeString() Py_XDECREF(compiledCode); Py_XDECREF(result); - if(success) emit finished(msg); - else emit error(msg, "", 0); + return success; } diff --git a/Code/Mantid/MantidPlot/src/PythonScript.h b/Code/Mantid/MantidPlot/src/PythonScript.h index 5b427fa1084d..86d13235632c 100644 --- a/Code/Mantid/MantidPlot/src/PythonScript.h +++ b/Code/Mantid/MantidPlot/src/PythonScript.h @@ -79,8 +79,6 @@ class PythonScript : public Script, MantidQt::API::WorkspaceObserver /// Create a list of keywords for the code completion API void generateAutoCompleteList(); - /// Construct the error message from the stack trace (if one exists) - QString constructErrorMsg(); /// Special handle for syntax errors as they have no traceback QString constructSyntaxErrorStr(PyObject *syntaxError); /// Convert a traceback to a string @@ -185,6 +183,9 @@ class PythonScript : public Script, MantidQt::API::WorkspaceObserver /// Delete a Python reference to the given workspace name void deletePythonReference(const std::string& wsName); + /// Send out an error and clear it from python. + void emit_error(); + PythonScripting * m_pythonEnv; PyObject *localDict, *stdoutSave, *stderrSave; PyObject *m_CodeFileObject;