On branch swig-py3: A follow up r1851888: save/restore Python error indicator For all callback APIs which don't return svn_error_t * cannot notify Python exception their caller, and as exceptions chain in Python 3, exception conext should be detached from caller. * subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (svn_swig_py_notify_func, svn_swig_py_notify_func2, svn_swig_py_status_func, svn_swig_py_client_status_func, svn_swig_py_status_func2, ra_callbacks_progress_func, svn_swig_py_config_enumerator2, svn_swig_py_config_section_enumerator2): Save error indicator before Python function call and then restore it after call Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (revision 1852824) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (working copy) @@ -2767,11 +2767,18 @@ PyObject *function = baton; PyObject *result; svn_error_t *err = SVN_NO_ERROR; + PyObject *exc, *exc_type, *exc_traceback; if (function == NULL || function == Py_None) return; svn_swig_py_acquire_py_lock(); + + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, #if IS_PY3 (char *)"(yiiyiii)", @@ -2796,6 +2803,9 @@ /* Our error has no place to go. :-( */ svn_error_clear(err); + /* Also, restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + svn_swig_py_release_py_lock(); } @@ -2807,6 +2817,7 @@ PyObject *function = baton; PyObject *result; svn_error_t *err = SVN_NO_ERROR; + PyObject *exc, *exc_type, *exc_traceback; if (function == NULL || function == Py_None) return; @@ -2813,6 +2824,11 @@ svn_swig_py_acquire_py_lock(); + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, (char *)"(O&O&)", make_ob_wc_notify, notify, @@ -2831,6 +2847,9 @@ /* Our error has no place to go. :-( */ svn_error_clear(err); + /* Also, restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + svn_swig_py_release_py_lock(); } @@ -2841,11 +2860,18 @@ PyObject *function = baton; PyObject *result; svn_error_t *err = SVN_NO_ERROR; + PyObject *exc, *exc_type, *exc_traceback; if (function == NULL || function == Py_None) return; svn_swig_py_acquire_py_lock(); + + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, (char *)SVN_SWIG_BYTES_FMT "O&", path, make_ob_wc_status, status)) == NULL) @@ -2863,6 +2889,9 @@ /* Our error has no place to go. :-( */ svn_error_clear(err); + /* Also, restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + svn_swig_py_release_py_lock(); } @@ -2874,11 +2903,18 @@ PyObject *function = baton; PyObject *result; svn_error_t *err = SVN_NO_ERROR; + PyObject *exc, *exc_type, *exc_traceback; if (function == NULL || function == Py_None) return; svn_swig_py_acquire_py_lock(); + + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, #if IS_PY3 (char *)"yO&O&", @@ -2902,6 +2938,9 @@ /* Our error has no place to go. :-( */ svn_error_clear(err); + /* Also, restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + svn_swig_py_release_py_lock(); } @@ -2965,11 +3004,18 @@ PyObject *function = baton; PyObject *result; svn_error_t *err = SVN_NO_ERROR; + PyObject *exc, *exc_type, *exc_traceback; if (function == NULL || function == Py_None) return; svn_swig_py_acquire_py_lock(); + + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, (char *)SVN_SWIG_BYTES_FMT "O&", path, make_ob_wc_status, status)) == NULL) @@ -2985,12 +3031,11 @@ } /* Our error has no place to go. :-( */ - if (err) - { - svn_error_clear(err); - PyErr_Clear(); - } + svn_error_clear(err); + /* Also, restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + svn_swig_py_release_py_lock(); } @@ -4230,11 +4275,17 @@ { PyObject *callbacks = (PyObject *)baton; PyObject *py_callback, *py_progress, *py_total, *result; + PyObject *exc, *exc_type, *exc_traceback; py_progress = py_total = NULL; svn_swig_py_acquire_py_lock(); + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + py_callback = PyObject_GetAttrString(callbacks, (char *)"progress_func"); if (py_callback == NULL) @@ -4274,6 +4325,9 @@ Py_XDECREF(result); finished: + /* Restore error indicator */ + PyErr_Restore(exc_type, exc, exc_traceback); + Py_XDECREF(py_callback); Py_XDECREF(py_progress); Py_XDECREF(py_total); @@ -5134,9 +5188,15 @@ PyObject *result; svn_error_t *err = SVN_NO_ERROR; svn_boolean_t c_result; + PyObject *exc, *exc_type, *exc_traceback; svn_swig_py_acquire_py_lock(); + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, #if IS_PY3 (char *)"yyO&", @@ -5158,7 +5218,7 @@ /* Any Python exception we might have pending must be cleared, because the SWIG wrapper will not check for it, and return a value with the exception still set. */ - PyErr_Clear(); + PyErr_Restore(exc_type, exc, exc_traceback); if (err) { @@ -5186,9 +5246,15 @@ PyObject *result; svn_error_t *err = SVN_NO_ERROR; svn_boolean_t c_result; + PyObject *exc, *exc_type, *exc_traceback; svn_swig_py_acquire_py_lock(); + /* As caller can't understand Python context and we can't notify if + Python call back function raise exception to caller, we must catch it + if it is occurred, and restore error indicator */ + PyErr_Fetch(&exc_type, &exc, &exc_traceback); + if ((result = PyObject_CallFunction(function, (char *)SVN_SWIG_BYTES_FMT "O&", name, @@ -5205,8 +5271,9 @@ /* Any Python exception we might have pending must be cleared, because the SWIG wrapper will not check for it, and return a value with the exception still set. */ - PyErr_Clear(); + PyErr_Restore(exc_type, exc, exc_traceback); + if (err) { /* We can't return the error, but let's at least stop enumeration. */