@@ -46,30 +46,23 @@ namespace
4646{
4747
4848std::string formatInternal (
49- PyObject *exceptionPyObject, PyObject *valuePyObject, PyObject *tracebackPyObject ,
49+ const handle<> &exceptionHandle, const handle<> &valueHandle, const handle<> &tracebackHandle ,
5050 bool withStacktrace, int *lineNumber = nullptr
5151)
5252{
53- if ( !exceptionPyObject )
54- {
55- throw IECore::Exception ( " No Python exception set" );
56- }
57-
58- PyErr_NormalizeException ( &exceptionPyObject, &valuePyObject, &tracebackPyObject );
53+ object exception ( exceptionHandle );
5954
60- object exception ( ( handle<>( exceptionPyObject ) ) );
61-
62- // valuePyObject and tracebackPyObject may be null.
55+ // `valueHandle` and `tracebackHandle` may be null.
6356 object value;
64- if ( valuePyObject )
57+ if ( valueHandle )
6558 {
66- value = object ( handle<>( valuePyObject ) );
59+ value = object ( valueHandle );
6760 }
6861
6962 object traceback;
70- if ( tracebackPyObject )
63+ if ( tracebackHandle )
7164 {
72- traceback = object ( handle<>( tracebackPyObject ) );
65+ traceback = object ( tracebackHandle );
7366 }
7467
7568 if ( lineNumber )
@@ -102,6 +95,20 @@ std::string formatInternal(
10295 return s;
10396}
10497
98+ std::tuple<handle<>, handle<>, handle<>> currentPythonException ()
99+ {
100+ PyObject *exceptionPyObject, *valuePyObject, *tracebackPyObject;
101+ PyErr_Fetch ( &exceptionPyObject, &valuePyObject, &tracebackPyObject );
102+ if ( !exceptionPyObject )
103+ {
104+ throw IECore::Exception ( " No Python exception set" );
105+ }
106+
107+ PyErr_NormalizeException ( &exceptionPyObject, &valuePyObject, &tracebackPyObject );
108+
109+ return std::make_tuple ( handle<>( exceptionPyObject ), handle<>( allow_null ( valuePyObject ) ), handle<>( allow_null ( tracebackPyObject ) ) );
110+ }
111+
105112} // namespace
106113
107114namespace IECorePython
@@ -112,28 +119,26 @@ namespace ExceptionAlgo
112119
113120std::string formatPythonException ( bool withStacktrace, int *lineNumber )
114121{
115- PyObject *exceptionPyObject, *valuePyObject, *tracebackPyObject;
116- PyErr_Fetch ( &exceptionPyObject, &valuePyObject, &tracebackPyObject );
117- return formatInternal ( exceptionPyObject, valuePyObject, tracebackPyObject, withStacktrace, lineNumber );
122+ auto [exception, value, traceback] = currentPythonException ();
123+ return formatInternal ( exception, value, traceback, withStacktrace, lineNumber );
118124}
119125
120126void translatePythonException ( bool withStacktrace )
121127{
122- PyObject *exceptionPyObject, *valuePyObject, *tracebackPyObject;
123- PyErr_Fetch ( &exceptionPyObject, &valuePyObject, &tracebackPyObject );
128+ auto [exception, value, traceback] = currentPythonException ();
124129
125130 // If the python exception is one bound via IECorePython::ExceptionClass,
126131 // then we can extract and throw the C++ exception held internally.
127- if ( PyObject_HasAttrString ( valuePyObject , " __exceptionPointer" ) )
132+ if ( PyObject_HasAttrString ( value. get () , " __exceptionPointer" ) )
128133 {
129- object exceptionPointerMethod ( handle<>( PyObject_GetAttrString ( valuePyObject , " __exceptionPointer" ) ) );
134+ object exceptionPointerMethod ( handle<>( PyObject_GetAttrString ( value. get () , " __exceptionPointer" ) ) );
130135 object exceptionPointerObject = exceptionPointerMethod ();
131136 std::exception_ptr exceptionPointer = boost::python::extract<std::exception_ptr>( exceptionPointerObject )();
132137 std::rethrow_exception ( exceptionPointer );
133138 }
134139
135140 // Otherwise, we just throw a generic exception describing the python error.
136- throw IECore::Exception ( formatInternal ( exceptionPyObject, valuePyObject, tracebackPyObject , withStacktrace ) );
141+ throw IECore::Exception ( formatInternal ( exception, value, traceback , withStacktrace ) );
137142}
138143
139144} // namespace ExceptionAlgo
0 commit comments