[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: Help with Python SWIG bindings and callbacks

From: Lawrence Stewart <lstewart_at_room52.net>
Date: Mon, 25 Aug 2008 11:25:31 +1000

Lawrence Stewart wrote:
> Lawrence Stewart wrote:
>> Hi all,
>> I'm playing with the Python SWIG bindings for SVN 1.5.1 and have run
>> into a brick wall. I want to update a working copy from a python
>> script, and have a python function callback executed for each item
>> updated. The python code below hopefully illustrates what I'm trying
>> to do.
>> def update_callback(notify, pool):
>> print "in callback"
>> def update(wc, rev):
>> ctx = svn.client.svn_client_create_context()
>> ctx.notify_func2 = update_callback
>> r = svn.core.svn_opt_revision_t()
>> r.kind = svn.core.svn_opt_revision_head
>> result_rev = svn.client.svn_client_update(wc, r, True, ctx)
>> print "result_rev: %d" % result_rev
>> The update function does work and my working copy does get updated the
>> HEAD, but my callback is never executed.
>> I'm basing this code on the statement in
>> http://svn.collab.net/svn-doxygen/group__Update.html that says if
>> ctx->notify_func2 is not NULL it will be called for each item updated.
>> This of course may not work or be applicable in Python land... someone
>> please tell me if this is the case.
>> I've tried countless variations of the above code and changing
>> parameters to the callback, changing the way the callback is assigned
>> to the context object (I tried following the way it was done in the
>> client.py unit test file for a different callback type that is used)
>> etc. etc. without success.
>> I suspect my problem is that I just don't grok the translation that
>> SWIG is doing from the C API up into Python and therein lies the problem.
>> Any help in understanding what I'm doing wrong or how I can achieve
>> something equivalent would be greatly appreciated.
> Quick follow up... I just stumbled across this thread that describes
> what I'm trying to do.
> http://osdir.com/ml/programming.swig/2003-06/msg00058.html
> It provided the missing clue I needed to make this work.
> Apologies for the noise.

Ok, so I can now get the callback to fire, but the arguments passed to
it look like random pointer junk and python coredumps somewhere within
the svn.client.svn_client_update3() call after having executed the
update and a few callbacks. Here's the new code:

def update_callback(path, action, kind, mime_type, content_state,
prop_state, revision):

   print "callback\taction: %d\trev: %u" % (action,revision)

def update(wc, rev):

   ctx = svn.client.svn_client_ctx_t()

   #ctx.notify_func = svn.client.svn_swig_py_notify_func
   #ctx.notify_baton = update_callback

   ctx.notify_func2 = svn.client.svn_swig_py_notify_func
   ctx.notify_baton2 = update_callback

   r = svn.core.svn_opt_revision_t()
   r.kind = svn.core.svn_opt_revision_head

     result_revs = svn.client.svn_client_update3([wc], r,
svn.core.svn_depth_infinity, False, True, True, ctx)
     for result_rev in result_revs:
       print "result_rev: %d" % result_rev
       print "done"
   except svn.core.SubversionException, e:
     sys.stderr.write("Error (%d): %s\n" % (e.apr_err, e.message))
   except Exception, e:
     print "Unknown exception"
     print e

I've also added some debug printfs to the underlying C functions
svn_swig_py_notify_func() and svn_swig_py_notify_func2() in
swigutil_py.c to check which function is being called and if the
arguments coming into the C function are the same as what is being
reported by python.

Running the above code with a local working copy path and with my printf
enabled SWIG C code produces the following output on the console:

lstewart_at_lawrence1> ./submirror.py
result_rev: 1
svn_swig_py_notify_func path: action: 139968536 revision: 139968536
callback action: 139968536 rev: 139968536
svn_swig_py_notify_func path: (aW
         action: 139943960 revision: 16778452
callback action: 139943960 rev: 16778452
svn_swig_py_notify_func path: 3W
         action: 139792408 revision: 16778452
callback action: 139792408 rev: 16778452
svn_swig_py_notify_func path: U
                                 action: 139792408 revision: 0
Segmentation fault (core dumped)

The lines starting with "svn_swig_py_notify_func" are being printed from
the C code, the others are coming form the python callback. Running GDB
on the python core file and getting a backtrace results in:

(gdb) bt
#0 0x28255ad9 in strlen () from /lib/libc.so.7
#1 0x080c8847 in PyModule_AddIntConstant ()
#2 0x080c8269 in PyModule_AddIntConstant ()
#3 0x080c8466 in PyModule_AddIntConstant ()
#4 0x080c8944 in PyModule_AddIntConstant ()
#5 0x0805b2e7 in PyObject_CallFunction ()
#6 0x282d2223 in svn_swig_py_notify_func (baton=0x8503aac,
path=0x8581af8 "\020\022U\b\v",
     action=139792408, kind=139915304, mime_type=0x1 <Address 0x1 out of
prop_state=svn_wc_notify_state_inapplicable, revision=2)
#7 0x28391265 in svn_client__update_internal () from
#8 0x28391458 in svn_client_update3 () from
#9 0x28928c45 in _wrap_svn_client_update3 () from
#10 0x08059fe7 in PyObject_Call ()
#11 0x080acd4c in PyEval_CallObjectWithKeywords ()
#12 0x080ac5f4 in _PyBuiltin_Init ()
#13 0x080b18ee in PyEval_EvalFrameEx ()
#14 0x080b3109 in PyEval_EvalCodeEx ()
#15 0x080b15fa in PyEval_EvalFrameEx ()
#16 0x080b2425 in PyEval_EvalFrameEx ()
#17 0x080b3109 in PyEval_EvalCodeEx ()
#18 0x080b3257 in PyEval_EvalCode ()
#19 0x080ca8e6 in Py_CompileString ()
#20 0x080ca990 in PyRun_FileExFlags ()
#21 0x080cbe89 in PyRun_SimpleFileExFlags ()
#22 0x08056f91 in Py_Main ()
#23 0x08056455 in main ()

My current understanding is that instead of my current code, I should be
doing one of the following:

   ctx.notify_func2 = svn.client.svn_swig_py_notify_func2
   ctx.notify_baton2 = update_callback2

   Where svn.client.svn_swig_py_notify_func2 refers to the
svn_swig_py_notify_func2 C function in swigutil_py.c.

   update_callback2 would have a signature applicable to the call made
in svn_swig_py_notify_func2 which to me looks like it should be:

   update_callback2(notify, pool)

   ctx.notify_func = svn.client.svn_swig_py_notify_func
   ctx.notify_baton = update_callback

Option 1 looks to be the correct way forward, but there is no
svn.client.svn_swig_py_notify_func2 exported from the python svn.client
module. Anyone have thoughts on why this is the case?

Option 2 looks like it should work but the callback is not executed at
all when I change the code accordingly.

Even though my current callback gets executed, I think my current code
is confusing things because I'm setting ctx.func2 to the C function that
is supposed to be called as the regular ctx.func which takes more
arguments... hence the pointer junk. That's just speculation on my
behalf though as I'm still slowly getting my head around how the SWIG
C->Python code is working.

Any help would be greatly appreciated.


To unsubscribe, e-mail: dev-unsubscribe_at_subversion.tigris.org
For additional commands, e-mail: dev-help_at_subversion.tigris.org
Received on 2008-08-25 03:29:02 CEST

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.