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();