From ee67b85b58eac186875b12c14d7158dc0c692ccc Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 3 Aug 2017 16:22:40 +0100 Subject: [PATCH] When we hit an exception, pass the line number of the top-of-stack * This allows us to update the current line highlight before stopping. --- qrenderdoc/Code/pyrenderdoc/PythonContext.cpp | 41 ++++++++++++------- qrenderdoc/Code/pyrenderdoc/PythonContext.h | 4 +- qrenderdoc/Code/qrenderdoc.cpp | 2 +- qrenderdoc/Windows/PythonShell.cpp | 6 ++- qrenderdoc/Windows/PythonShell.h | 2 +- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp index cace6df30..2a1945903 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.cpp @@ -149,7 +149,7 @@ static PyMethodDef OutputRedirector_methods[] = { PyObject *PythonContext::main_dict = NULL; -void FetchException(QString &typeStr, QString &valueStr, QList &frames) +void FetchException(QString &typeStr, QString &valueStr, int &finalLine, QList &frames) { PyObject *exObj = NULL, *valueObj = NULL, *tracebackObj = NULL; @@ -184,6 +184,13 @@ void FetchException(QString &typeStr, QString &valueStr, QList &frames) PyObject *args = Py_BuildValue("(N)", tracebackObj); PyObject *formattedTB = PyObject_CallObject(func, args); + PyTracebackObject *tb = (PyTracebackObject *)tracebackObj; + + while(tb->tb_next) + tb = tb->tb_next; + + finalLine = tb->tb_lineno; + if(formattedTB) { Py_ssize_t size = PyList_Size(formattedTB); @@ -191,7 +198,7 @@ void FetchException(QString &typeStr, QString &valueStr, QList &frames) { PyObject *el = PyList_GetItem(formattedTB, i); - frames << ToQStr(el); + frames << ToQStr(el).trimmed(); } Py_DecRef(formattedTB); @@ -473,7 +480,8 @@ void PythonContext::executeString(const QString &filename, const QString &source { emit exception( lit("SystemError"), - tr("Python integration failed to initialise, see diagnostic log for more information."), {}); + tr("Python integration failed to initialise, see diagnostic log for more information."), -1, + {}); return; } @@ -519,18 +527,19 @@ void PythonContext::executeString(const QString &filename, const QString &source QString typeStr; QString valueStr; + int finalLine = -1; QList frames; bool caughtException = (ret == NULL); if(caughtException) - FetchException(typeStr, valueStr, frames); + FetchException(typeStr, valueStr, finalLine, frames); Py_XDECREF(ret); PyGILState_Release(gil); if(caughtException) - emit exception(typeStr, valueStr, frames); + emit exception(typeStr, valueStr, finalLine, frames); } void PythonContext::executeString(const QString &source, bool interactive) @@ -544,7 +553,8 @@ void PythonContext::executeFile(const QString &filename) if(!f.exists()) { - emit exception(lit("FileNotFoundError"), tr("No such file or directory: %1").arg(filename), {}); + emit exception(lit("FileNotFoundError"), tr("No such file or directory: %1").arg(filename), -1, + {}); return; } @@ -556,7 +566,7 @@ void PythonContext::executeFile(const QString &filename) } else { - emit exception(lit("IOError"), QFormatStr("%1: %2").arg(f.errorString()).arg(filename), {}); + emit exception(lit("IOError"), QFormatStr("%1: %2").arg(f.errorString()).arg(filename), -1, {}); } } @@ -566,7 +576,8 @@ void PythonContext::setGlobal(const char *varName, const char *typeName, void *o { emit exception( lit("SystemError"), - tr("Python integration failed to initialise, see diagnostic log for more information."), {}); + tr("Python integration failed to initialise, see diagnostic log for more information."), -1, + {}); return; } @@ -587,7 +598,7 @@ void PythonContext::setGlobal(const char *varName, const char *typeName, void *o emit exception(lit("RuntimeError"), tr("Failed to set variable '%1' of type '%2'") .arg(QString::fromUtf8(varName)) .arg(QString::fromUtf8(typeName)), - {}); + -1, {}); return; } @@ -694,7 +705,8 @@ void PythonContext::setPyGlobal(const char *varName, PyObject *obj) { emit exception( lit("SystemError"), - tr("Python integration failed to initialise, see diagnostic log for more information."), {}); + tr("Python integration failed to initialise, see diagnostic log for more information."), -1, + {}); return; } @@ -711,7 +723,7 @@ void PythonContext::setPyGlobal(const char *varName, PyObject *obj) return; emit exception(lit("RuntimeError"), - tr("Failed to set variable '%1'").arg(QString::fromUtf8(varName)), {}); + tr("Failed to set variable '%1'").arg(QString::fromUtf8(varName)), -1, {}); } void PythonContext::outstream_del(PyObject *self) @@ -821,13 +833,14 @@ extern "C" void HandleException(PyObject *global_handle) { QString typeStr; QString valueStr; + int finalLine = -1; QList frames; - FetchException(typeStr, valueStr, frames); + FetchException(typeStr, valueStr, finalLine, frames); OutputRedirector *redirector = (OutputRedirector *)global_handle; - if(redirector->context) - emit redirector->context->exception(typeStr, valueStr, frames); + if(redirector && redirector->context) + emit redirector->context->exception(typeStr, valueStr, finalLine, frames); } extern "C" bool IsThreadBlocking(PyObject *global_handle) diff --git a/qrenderdoc/Code/pyrenderdoc/PythonContext.h b/qrenderdoc/Code/pyrenderdoc/PythonContext.h index c2268a6b2..45ac84ebc 100644 --- a/qrenderdoc/Code/pyrenderdoc/PythonContext.h +++ b/qrenderdoc/Code/pyrenderdoc/PythonContext.h @@ -80,7 +80,7 @@ public: emit exception(lit("RuntimeError"), tr("Failed to set variable '%1' of type '%2'") .arg(QString::fromUtf8(varName)) .arg(QString::fromUtf8(typeName)), - {}); + -1, {}); } static PyObject *QWidgetToPy(PyObject *self, QWidget *widget) @@ -97,7 +97,7 @@ public: int currentLine() { return location.line; } signals: void traceLine(const QString &file, int line); - void exception(const QString &type, const QString &value, QList frames); + void exception(const QString &type, const QString &value, int finalLine, QList frames); void textOutput(bool isStdError, const QString &output); public slots: diff --git a/qrenderdoc/Code/qrenderdoc.cpp b/qrenderdoc/Code/qrenderdoc.cpp index b714d3c4d..b5d7d2b60 100644 --- a/qrenderdoc/Code/qrenderdoc.cpp +++ b/qrenderdoc/Code/qrenderdoc.cpp @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) py.ctx().setGlobal("pyrenderdoc", (ICaptureContext *)&ctx); QObject::connect(&py.ctx(), &PythonContext::exception, - [](const QString &type, const QString &value, QList frames) { + [](const QString &type, const QString &value, int, QList frames) { QString exString; diff --git a/qrenderdoc/Windows/PythonShell.cpp b/qrenderdoc/Windows/PythonShell.cpp index fe02d4943..cf7f74df0 100644 --- a/qrenderdoc/Windows/PythonShell.cpp +++ b/qrenderdoc/Windows/PythonShell.cpp @@ -569,7 +569,8 @@ void PythonShell::traceLine(const QString &file, int line) scriptEditor->markerAdd(line > 0 ? line - 1 : 0, CURRENT_MARKER + 1); } -void PythonShell::exception(const QString &type, const QString &value, QList frames) +void PythonShell::exception(const QString &type, const QString &value, int finalLine, + QList frames) { QTextEdit *out = ui->scriptOutput; if(QObject::sender() == (QObject *)interactiveContext) @@ -577,6 +578,9 @@ void PythonShell::exception(const QString &type, const QString &value, QList= 0) + traceLine(QString(), finalLine); + if(!out->toPlainText().endsWith(QLatin1Char('\n'))) exString = lit("\n"); if(!frames.isEmpty()) diff --git a/qrenderdoc/Windows/PythonShell.h b/qrenderdoc/Windows/PythonShell.h index 658160fdf..48810c74c 100644 --- a/qrenderdoc/Windows/PythonShell.h +++ b/qrenderdoc/Windows/PythonShell.h @@ -62,7 +62,7 @@ private slots: // manual slots void interactive_keypress(QKeyEvent *e); void traceLine(const QString &file, int line); - void exception(const QString &type, const QString &value, QList frames); + void exception(const QString &type, const QString &value, int finalLine, QList frames); void textOutput(bool isStdError, const QString &output); private: