On 2020/07/29 1:02, Yasuhito FUTATSUKI wrote: > On 2020/07/28 23:34, C. Michael Pilato wrote: >> Hey, all. >> >> I'm writing some code that performs commits via the Subversion Python >> bindings, and I'm struggling to understand some things I see there. >> >> In the svn_fs.i interface file, there's this block of code: >> >> /* ----------------------------------------------------------------------- >> Fix the return value for svn_fs_commit_txn(). If the conflict result is >> NULL, then %append_output() is passed Py_None, but that goofs up >> because that is *also* the marker for "I haven't started assembling a >> multi-valued return yet" which means the second return value (new_rev) >> will not cause a 2-tuple to be manufactured. >> >> The answer is to explicitly create a 2-tuple return value. >> >> FIXME: Do the Perl and Ruby bindings need to do something similar? >> */ >> #ifdef SWIGPYTHON >> %typemap(argout) (const char **conflict_p, svn_revnum_t *new_rev) { >> /* this is always Py_None */ >> Py_DECREF($result); >> /* build the result tuple */ >> $result = Py_BuildValue("zi", *$1, (long)*$2); >> } >> #endif > > Ah, it returns a tuple of str and int, not a tuple of bytes and int.
I made a patch addressing to it, as attached swig-py-fix-svn_fs_commit-patch.txt. (Only affect on Python 3, no function change on Python 2.7) >> This reads and claims to behave exactly as I'd expect, given the dual >> return values of svn_fs_commit_txn (and svn_repos_fs_commit_txn which wraps >> it). And since this interface file is included from svn_repos.i, I would >> expect those typemaps to apply also to svn_repos_fs_commit_txn, which has >> matching parameter types and names. > > It seems it isn't match because svn_repos_fs_commit_txn have extra > argument "svn_repos_t *repos" between them. > >> But this isn't how the code appears to work in practice. A successful >> commit gets back from svn.repos.fs_commit_txn not a 2-tuple, but just the >> newly created revision number. Moreover, if my commit succeeds but the >> post-commit hook fails, svn.repos.fs_commit_txn() raises an Exception, >> masking the return of the newly created revision number altogether. Now, >> the masked revision number thing I can understand -- it's hard to do in >> Python what we promise to do in C (which is to return an svn_error_t but >> still set the new_rev return value). But the 2-tuple thing I have no >> explanation for. Any ideas? > > I think it is need one more typemap for it in svn_repos.i like > > [[[ > #ifdef SWIGPYTHON > %typemap(argout) (const char **conflict_p, svn_repos_t *repos, svn_revnum_t > *new_rev) { > /* this is always Py_None */ > Py_DECREF($result); > /* build the result tuple */ > $result = Py_BuildValue("zi", *$1, (long)*$3); > } > #endif > ]]] Also I made a patch for it, based on fixed typemap for svn_fs_commit_txn, as attached swig-py-fix-svn_repos_fs_commit-patch.txt Difference on SWIG generated subversion/bindings/swig/python/svn_repos.c between before and after this patch is below. (SWIG 3.0.12, for Python 3) [[[ --- subversion/bindings/swig/python/svn_repos.c.before_patch 2020-07-29 05:45:35.626521000 +0900 +++ subversion/bindings/swig/python/svn_repos.c 2020-07-29 06:41:51.220682000 +0900 @@ -12126,23 +12126,16 @@ resultobj = Py_None; } { - PyObject *s; - if (*arg1 == NULL) { - Py_INCREF(Py_None); - s = Py_None; - } - else { - s = PyBytes_FromString(*arg1); - if (s == NULL) - SWIG_fail; - } - resultobj = SWIG_Python_AppendOutput(resultobj, s); - } - if (SWIG_IsTmpObj(res3)) { - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_long((*arg3))); - } else { - int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN | 0 ) : 0 ; - resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_long, new_flags)); + /* this is always Py_None */ + Py_DECREF(resultobj); + /* build the result tuple */ + resultobj = Py_BuildValue( + #if PY_VERSION_HEX >= 0x03000000 + "yi", + #else + "zi", + #endif + *arg1, (long)*arg3); } { Py_XDECREF(_global_py_pool); ]]] I couldn't make test cases for them, so I didn't test, yet. Cheers, -- Yasuhito FUTATSUKI <futat...@yf.bsclub.org>
swig-py: Fix return type of svn_fs_commit_txn() on Python 3. * subversion/bindings/swig/svn_fs.i (%typemap(argout) (const char **conflict_p, svn_revnum_t *new_rev)): Use "bytes or None" conversion to build return value on Python 3. Index: subversion/bindings/swig/svn_fs.i =================================================================== --- subversion/bindings/swig/svn_fs.i (revision 1880203) +++ subversion/bindings/swig/svn_fs.i (working copy) @@ -108,7 +108,13 @@ /* this is always Py_None */ Py_DECREF($result); /* build the result tuple */ - $result = Py_BuildValue("zi", *$1, (long)*$2); + $result = Py_BuildValue( +%#if PY_VERSION_HEX >= 0x03000000 + "yi", +%#else + "zi", +%#endif + *$1, (long)*$2); } #endif
swig-py: Fix return value of svn_repos_fs_commit_txn(). * subversion/bindings/swig/svn_repos.i (typemap(argout) (const char **conflict_p, svn_repos_t *repos, svn_revnum_t *new_rev)): New typemap. Found by: cmpilato Index: subversion/bindings/swig/svn_repos.i =================================================================== --- subversion/bindings/swig/svn_repos.i (revision 1880203) +++ subversion/bindings/swig/svn_repos.i (working copy) @@ -109,6 +109,32 @@ #endif /* ----------------------------------------------------------------------- + Fix the return value for svn_repos_fs_commit_txn(). If the conflict + result is NULL, then %append_output() is passed Py_None, but that goofs + up because that is *also* the marker for "I haven't started assembling + a multi-valued return yet" which means the second return value + (new_rev) will not cause a 2-tuple to be manufactured. + + The answer is to explicitly create a 2-tuple return value. + + FIXME: Do the Perl and Ruby bindings need to do something similar? +*/ +#ifdef SWIGPYTHON +%typemap(argout) (const char **conflict_p, svn_repos_t *repos, + svn_revnum_t *new_rev) { + /* this is always Py_None */ + Py_DECREF($result); + /* build the result tuple */ + $result = Py_BuildValue( +%#if PY_VERSION_HEX >= 0x03000000 + "yi", +%#else + "zi", +%#endif + *$1, (long)*$3); +} +#endif +/* ----------------------------------------------------------------------- handle svn_repos_get_committed_info(). */ #ifdef SWIGRUBY