Skip to content

Commit

Permalink
Add support for VirtualErrorHandlers in core sip
Browse files Browse the repository at this point in the history
Unfortunately requires a bunch of code to be duplicated from
QgsPythonUtilsImpl::getTraceback() into core.sip, but there's no way
to avoid this
  • Loading branch information
nyalldawson committed Jun 23, 2017
1 parent 53e7ef8 commit d63d560
Showing 1 changed file with 91 additions and 0 deletions.
91 changes: 91 additions & 0 deletions python/core/core.sip
Original file line number Diff line number Diff line change
@@ -1,6 +1,93 @@
%Module(name=qgis._core,
keyword_arguments="Optional")

%ModuleCode

#include "qgsprocessingexception.h"

QString getTraceback()
{
#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}

// acquire global interpreter lock to ensure we are in a consistent state
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

QString errMsg;
QString result;

PyObject *modStringIO = nullptr;
PyObject *modTB = nullptr;
PyObject *obStringIO = nullptr;
PyObject *obResult = nullptr;

PyObject *type, *value, *traceback;

PyErr_Fetch( &type, &value, &traceback );
PyErr_NormalizeException( &type, &value, &traceback );

const char *iomod = "io";

modStringIO = PyImport_ImportModule( iomod );
if ( !modStringIO )
TRACEBACK_FETCH_ERROR( QString( "can't import %1" ).arg( iomod ) );

obStringIO = PyObject_CallMethod( modStringIO, ( char * ) "StringIO", nullptr );

/* Construct a cStringIO object */
if ( !obStringIO )
TRACEBACK_FETCH_ERROR( "cStringIO.StringIO() failed" );

modTB = PyImport_ImportModule( "traceback" );
if ( !modTB )
TRACEBACK_FETCH_ERROR( "can't import traceback" );

obResult = PyObject_CallMethod( modTB, ( char * ) "print_exception",
( char * ) "OOOOO",
type, value ? value : Py_None,
traceback ? traceback : Py_None,
Py_None,
obStringIO );

if ( !obResult )
TRACEBACK_FETCH_ERROR( "traceback.print_exception() failed" );

Py_DECREF( obResult );

obResult = PyObject_CallMethod( obStringIO, ( char * ) "getvalue", nullptr );
if ( !obResult )
TRACEBACK_FETCH_ERROR( "getvalue() failed." );

/* And it should be a string all ready to go - duplicate it. */
if ( !PyUnicode_Check( obResult ) )
TRACEBACK_FETCH_ERROR( "getvalue() did not return a string" );

result = QString::fromUtf8( PyUnicode_AsUTF8( obResult ) );

done:

// All finished - first see if we encountered an error
if ( result.isEmpty() && !errMsg.isEmpty() )
{
result = errMsg;
}

Py_XDECREF( modStringIO );
Py_XDECREF( modTB );
Py_XDECREF( obStringIO );
Py_XDECREF( obResult );
Py_XDECREF( value );
Py_XDECREF( traceback );
Py_XDECREF( type );

// we are done calling python API, release global interpreter lock
PyGILState_Release( gstate );

return result;
}

%End

%Import QtXml/QtXmlmod.sip
%Import QtNetwork/QtNetworkmod.sip
%Import QtSql/QtSqlmod.sip
Expand Down Expand Up @@ -413,3 +500,7 @@
%Include expression/qgsexpressionnodeimpl.sip
%Include expression/qgsexpressionnode.sip
%Include expression/qgsexpressionfunction.sip

%VirtualErrorHandler processing_exception_handler
throw QgsProcessingException( getTraceback() );
%End

0 comments on commit d63d560

Please sign in to comment.