Hi all, The svn_repos_history2() function allows the history_func() to return a special error, SVN_ERR_CEASE_INVOCATION, to stop the search. This is not supported in Python bindings, though: attempt to return core.SVN_ERR_CEASE_INVOCATION from the history receiver results in an exception:
def history_lookup(path, rev, pool): return core.SVN_ERR_CEASE_INVOCATION repos.svn_repos_history2(..., history_lookup, ...) svn.core.SubversionException: ('Python callback returned an invalid object', 20014) Indeed, svn_swig_py_repos_history_func() only expects a return of None. This patch allows the callback to return core.SVN_ERR_CEASE_INVOCATION. Currently, this is only used in svn_repos_history2() - apparently, it's the only function that supports SVN_ERR_CEASE_INVOCATION. However, there is a FIXME at least in copyfrom_info_receiver() in libsvn_client/log.c, stating that other callbacks may eventually be able to return SVN_ERR_CEASE_INVOCATION as well. Regards, Alexey.
Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (revision 923895) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (working copy) @@ -1343,7 +1343,26 @@ "Error converting object of type '%s'", datatype); } +/* Allow None (for SVN_NO_ERROR) and SVN_ERR_CEASE_INVOCATION for callback returns */ +static svn_error_t *callback_none_or_cease(PyObject *result) +{ + long rv; + if (result == Py_None) + return SVN_NO_ERROR; + + if (PyInt_Check(result)) + rv = PyInt_AsLong(result); + else if (PyLong_Check(result)) + rv = PyLong_AsLong(result); + else + return callback_bad_return_error("Neither None nor integer"); + if (rv == SVN_ERR_CEASE_INVOCATION) + return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, "Stop requested by callback"); + else + return callback_bad_return_error("Unexpected return value from callback"); +} + /*** Editor Wrapping ***/ @@ -2388,7 +2407,7 @@ { PyObject *function = baton; PyObject *result; - svn_error_t *err = SVN_NO_ERROR; + svn_error_t *err; if (function == NULL || function == Py_None) return SVN_NO_ERROR; @@ -2403,8 +2422,7 @@ } else { - if (result != Py_None) - err = callback_bad_return_error("Not None"); + err = callback_none_or_cease(result); Py_DECREF(result); } svn_swig_py_release_py_lock();