mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-10-31 00:06:02 -04:00 
			
		
		
		
	closes: https://github.com/qgis/QGIS/issues/56944 Signed-off-by: t0b3 <thomas.bettler@gmail.com>
		
			
				
	
	
		
			160 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			160 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| %Module(name=qgis._core,
 | |
|         keyword_arguments="All")
 | |
| 
 | |
| ${DEFAULTDOCSTRINGSIGNATURE}
 | |
| 
 | |
| %ModuleCode
 | |
| 
 | |
| #include "qgsexception.h"
 | |
| #include "qgslogger.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
 | |
| 
 | |
| %Feature HAVE_GUI
 | |
| %Feature HAVE_QTSERIALPORT
 | |
| %Feature HAVE_QTPRINTER
 | |
| %Feature ANDROID
 | |
| %Feature VECTOR_MAPPED_TYPE
 | |
| %Feature HAVE_WEBENGINE_SIP
 | |
| %Feature PYQT6
 | |
| 
 | |
| %Import QtXml/QtXmlmod.sip
 | |
| %Import QtNetwork/QtNetworkmod.sip
 | |
| %Import QtSql/QtSqlmod.sip
 | |
| 
 | |
| %Import QtPrintSupport/QtPrintSupportmod.sip
 | |
| %Import QtWidgets/QtWidgetsmod.sip
 | |
| %Import QtPositioning/QtPositioningmod.sip
 | |
| 
 | |
| %If (HAVE_QTSERIALPORT)
 | |
| %Import QtSerialPort/QtSerialPortmod.sip
 | |
| %End
 | |
| 
 | |
| %Include conversions.sip
 | |
| %Include qgsexception.sip
 | |
| %Include typedefs.sip
 | |
| %Include std.sip
 | |
| 
 | |
| 
 | |
| %Include core_auto.sip
 | |
| 
 | |
| %VirtualErrorHandler processing_exception_handler
 | |
|     // if an explicit QgsProcessingException was raised, we don't retrieve
 | |
|     // and append the trace. It's too noisy for these "expected" type errors.
 | |
|     // For all other exceptions, it's likely a coding error in the algorithm,
 | |
|     // so we DO retrieve the full traceback for debugging.
 | |
|     PyGILState_STATE gstate;
 | |
|     gstate = PyGILState_Ensure();
 | |
|     PyTypeObject* err = reinterpret_cast< PyTypeObject* >( PyErr_Occurred() );
 | |
|     const bool isProcessingException = err && QString( err->tp_name ) == QStringLiteral( "QgsProcessingException" );
 | |
| 
 | |
|     QString what;
 | |
|     if ( isProcessingException )
 | |
|     {
 | |
|       PyObject *type, *value, *traceback;
 | |
|       PyErr_Fetch( &type, &value, &traceback );
 | |
|       // check whether the object is already a unicode string
 | |
|       if ( PyUnicode_Check( value) )
 | |
|       {
 | |
|         what = QString::fromUtf8( PyUnicode_AsUTF8( value ) );
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         PyObject* str = PyObject_Str( value );
 | |
|         what = QString::fromUtf8( PyUnicode_AsUTF8( str ) );
 | |
|         Py_XDECREF( str );
 | |
|       }
 | |
|       PyGILState_Release( gstate );
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       PyGILState_Release( gstate );
 | |
|       QString trace = getTraceback();
 | |
|       QgsLogger::critical( trace );
 | |
|       what = trace;
 | |
|     }
 | |
|     SIP_RELEASE_GIL( sipGILState );
 | |
|     throw QgsProcessingException( what );
 | |
| %End
 |