Index: subversion/bindings/swig/python/tests/ra.py =================================================================== --- subversion/bindings/swig/python/tests/ra.py (revision 31270) +++ subversion/bindings/swig/python/tests/ra.py (working copy) @@ -2,6 +2,7 @@ from svn import core, repos, fs, delta, client, ra from StringIO import StringIO +import weakref from trac.versioncontrol.tests.svn_fs import SubversionRepositoryTestSetup, \ REPOS_PATH, REPOS_URL @@ -340,10 +341,29 @@ reporter, reporter_baton = ra.do_update(self.ra_ctx, 10, "", True, e_ptr, e_baton) + pool = weakref.ref(e_ptr._parent_pool) + + # Verify that pool still exists after deleting the editor ptr and baton + self.assertEquals(len(reporter._parent_pool._kids), 1) + del e_ptr + del e_baton + self.assert_(pool() is not None, "Editor pool should still exist") + + weak_editor = weakref.ref(editor) + del editor + self.assert_(weak_editor() is not None, "Python editor should still exist") + reporter.set_path(reporter_baton, "", 0, True, None) reporter.finish_report(reporter_baton) + # Verify that pool is deleted after reporter is deleted + del reporter + del reporter_baton + self.assert_(pool() is None, "Editor pool should be dead now") + self.assert_(weak_editor() is None, "Python editor should be dead now") + + def test_namestring(self): # Only ra-{neon,serf} support this right now. if REPOS_URL.startswith('http'): Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (revision 31270) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (working copy) @@ -114,6 +114,7 @@ static char assertValid[] = "assert_valid"; static char markValid[] = "_mark_valid"; static char parentPool[] = "_parent_pool"; +static char addKid[] = "_add_kid"; static char wrap[] = "_wrap"; static char unwrap[] = "_unwrap"; static char setParentPool[] = "set_parent_pool"; @@ -202,6 +203,12 @@ application_py_pool = NULL; } +/* Add a kid to the specified pool */ +PyObject *svn_swig_py_add_kid_to_pool(PyObject *py_pool, PyObject *kid) +{ + return PyObject_CallMethod(py_pool, addKid, objectTuple, kid); +} + /* Set the parent pool of a proxy object */ static int proxy_set_pool(PyObject **proxy, PyObject *pool) { Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h (revision 31270) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h (working copy) @@ -92,6 +92,11 @@ int svn_swig_py_get_parent_pool(PyObject *args, swig_type_info *type, PyObject **py_pool, apr_pool_t **pool); +/* Add a kid to the pool so that he doesn't die until the pool dies */ +SVN_SWIG_SWIGUTIL_EXPORT +PyObject *svn_swig_py_add_kid_to_pool(PyObject *py_pool, PyObject *kid); + + /*** SWIG Wrappers ***/ Index: subversion/bindings/swig/include/proxy_apr.swg =================================================================== --- subversion/bindings/swig/include/proxy_apr.swg (revision 31270) +++ subversion/bindings/swig/include/proxy_apr.swg (working copy) @@ -116,6 +116,7 @@ self._apr_pool_destroy = _core.apr_pool_destroy self._svn_swig_py_clear_application_pool = \ _core.svn_swig_py_clear_application_pool + self._kids = [] # If we are an application-level pool, # then set this pool to be the application-level pool @@ -137,7 +138,11 @@ def clear(self): """Clear embedded memory pool. Invalidate all subpools.""" pool = self._parent_pool + + # Clear pool and release kids apr_pool_clear(self) + self._kids = [] + self.set_parent_pool(pool) def destroy(self): @@ -153,6 +158,9 @@ # Destroy pool self._apr_pool_destroy(self) + # Release the kids + self._kids = [] + # Clear application pool if necessary if is_application_pool: application_pool = None @@ -203,6 +211,11 @@ else: return GenericSWIGWrapper(obj, self) + def _add_kid(self, obj): + """Add a kid to the pool to make sure it lives as long as the pool""" + self._kids.append(obj) + + %} } }; Index: subversion/bindings/swig/svn_delta.i =================================================================== --- subversion/bindings/swig/svn_delta.i (revision 31270) +++ subversion/bindings/swig/svn_delta.i (working copy) @@ -53,11 +53,56 @@ thunk editors for the various language bindings. */ +/* Make sure the Python version of the editor lives as long + as the editor objects we return. */ #ifdef SWIGPYTHON +%typemap(in) (PyObject *py_editor) +{ + /* Save editor in pool */ + PyObject *result = svn_swig_py_add_kid_to_pool(_global_py_pool, $input); + if (result == NULL) SWIG_fail; + Py_DECREF(result); + + /* Convert argument */ + $1 = $input; +} + void svn_swig_py_make_editor(const svn_delta_editor_t **editor, void **edit_baton, PyObject *py_editor, apr_pool_t *pool); + + + +/* If we return any objects, make sure that our editor lives as long + as the returned objects. Do this by saving our editor in the + current pool. */ +%typemap(in) (const svn_delta_editor_t *EDITOR) +{ + /* Save editor in pool */ + PyObject *result = svn_swig_py_add_kid_to_pool(_global_py_pool, $input); + if (result == NULL) SWIG_fail; + Py_DECREF(result); + + /* Convert argument */ + $1 = ($1_ltype)svn_swig_MustGetPtr($input, $descriptor, $svn_argnum); + if (PyErr_Occurred()) { + SWIG_fail; + } +} + + +%apply (const svn_delta_editor_t *EDITOR) +{ + const svn_delta_editor_t *editor, + const svn_delta_editor_t *editor, + const svn_delta_editor_t *editor, + const svn_delta_editor_t *diff_editor, + const svn_delta_editor_t *update_editor, + const svn_delta_editor_t *switch_editor, + const svn_delta_editor_t *status_editor +} + #endif #ifdef SWIGPERL