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

Reply via email to