Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 56 additions & 30 deletions src/IECorePython/ExceptionAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,51 +58,77 @@ std::string formatPythonException( bool withStacktrace, int *lineNumber )
throw IECore::Exception( "No Python exception set" );
}

PyErr_NormalizeException( &exceptionPyObject, &valuePyObject, &tracebackPyObject );

object exception( ( handle<>( exceptionPyObject ) ) );

// valuePyObject and tracebackPyObject may be null.
object value;
std::string simpleFormat = "Could not get exception text\n";
if( valuePyObject )
{
value = object( handle<>( valuePyObject ) );
simpleFormat = PyString_AsString(valuePyObject) + std::string( "\n" );
}

object traceback;
if( tracebackPyObject )
{
traceback = object( handle<>( tracebackPyObject ) );
}
PyErr_NormalizeException( &exceptionPyObject, &valuePyObject, &tracebackPyObject );

if( lineNumber )

try
{
if( PyErr_GivenExceptionMatches( value.ptr(), PyExc_SyntaxError ) )
object exception( ( handle<>( exceptionPyObject ) ) );

// valuePyObject and tracebackPyObject may be null.
object value;
if( valuePyObject )
{
*lineNumber = extract<int>( value.attr( "lineno" ) );
value = object( handle<>( valuePyObject ) );
}
else if( traceback )

object traceback;
if( tracebackPyObject )
{
*lineNumber = extract<int>( traceback.attr( "tb_lineno" ) );
traceback = object( handle<>( tracebackPyObject ) );

simpleFormat += "Simple Traceback:\n";
object curTraceback = traceback;
while( curTraceback )
{
std::string filename = extract<std::string>( curTraceback.attr( "tb_frame" ).attr( "f_code" ).attr( "co_filename" ) );
int lineNo = extract<int>( curTraceback.attr( "tb_frame" ).attr("f_lineno") );
simpleFormat += filename + " : Line " + std::to_string( lineNo ) + "\n";
curTraceback = curTraceback.attr( "tb_next" );
}
}

if( lineNumber )
{
if( PyErr_GivenExceptionMatches( value.ptr(), PyExc_SyntaxError ) )
{
*lineNumber = extract<int>( value.attr( "lineno" ) );
}
else if( traceback )
{
*lineNumber = extract<int>( traceback.attr( "tb_lineno" ) );
}
}
}

object tracebackModule( import( "traceback" ) );
object tracebackModule( import( "traceback" ) );

object formattedList;
if( withStacktrace )
{
formattedList = tracebackModule.attr( "format_exception" )( exception, value, traceback );
object formattedList;
if( withStacktrace )
{
formattedList = tracebackModule.attr( "format_exception" )( exception, value, traceback );
}
else
{
formattedList = tracebackModule.attr( "format_exception_only" )( exception, value );
}

object formatted = str( "" ).join( formattedList );
std::string s = extract<std::string>( formatted );

return s;
}
else
catch( boost::python::error_already_set &e )
{
formattedList = tracebackModule.attr( "format_exception_only" )( exception, value );
PyObject *ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When PyErr_Fetch has returned, we own a reference to ptype, pvalue and ptraceback. In the existing code we use a handle or object to wrap these, and that takes care of dropping the reference automatically. Otherwise the manual reference counting required by the Python API is just too error prone...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had originally tried something like this, but found that after the other stuff had tried to run, it seemed to have somehow invalidated "value", and my simple code wouldn't work any more, which is why I moved it earlier. There doesn't seem to be any good reason for this though, so if you think this is actually the right approach, then we just need to debug that.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did wonder if that might have been the case, but I couldn't think of a reason why. Worth revisiting briefly I reckon...

return std::string( "Python exception can't be formatted nicely due to Python failure: " ) + PyString_AsString( pvalue ) + "\nOriginal exception is: " + simpleFormat;
}

object formatted = str( "" ).join( formattedList );
std::string s = extract<std::string>( formatted );

return s;
}

void translatePythonException( bool withStacktrace )
Expand Down