Lost in __setstate__() in C++ and swig

Amaury Forgeot d'Arc afaNOSPAM at neuf.fr
Thu Sep 13 18:24:15 EDT 2007


Hello,

Martin Drautzburg a écrit :
> I am trying to cPickle/unpickle a C++ extension class with some private
> data members. I wrote __getstate__() and __setstate__ in C++ (I have
> to, due to the private data). Pickling writes the following file:
> 
>         ccopy_reg
>         _reconstructor
>         p1
>         (cpyramid
>         MidiBytes
>         p2
>         c__builtin__
>         object
>         p3
>         NtRp4
>         (S'some unknown MidiBytes'
>         I1
>         I2
>         I3
>         tb.
> 
> But when unpickling I get the following error
> 
>         TypeError: in method 'MidiBytes___setstate__', argument 1 of type 
>         'pyramid::MidiBytes *'
> 
> I debugged the swig wrapper and indeed the wrapper is called with just
> one tuple argument. No object seems to be present at the time.
> 
> All the examples I've seen use python functions for __getstate__ and
> __setstate__ and it seems to me that the object itself is already there
> when __setstate__ is called. 

Unpickling an object does not use the normal path for creating the 
object. More precisely, the __init__ method is not called! See
http://docs.python.org/dev/library/pickle.html#pickling-and-unpickling-normal-class-instances

I suggest that you try to play with __getinitargs__ or __getnewargs__.
By calling __init__, it will give a chance to Swig to allocate the C++ 
object.

> 
> In a moment of dispair I declared __setstate__() static and have it
> create and return a MidiBytes object. 
> 
>         MidiBytes *MidiBytes:: __setstate__ (PyObject * aTuple) {
>                 return new MidiBytes();
>         }
> 
> Then unpickling no longer complains about "argument 1", but the
> unpickled object does not work
> 
>         >>> nn = cPickle.load(FILE)
>         >>> nn.len()
>         Traceback (most recent call last):
>           File "<stdin>", line 1, in ?
>           File "/usr/src/sound.d/pyramid/pyramid.py", line 618, in len
>             return _pyramid.MidiBytes_len(*args)
>         TypeError: in method 'MidiBytes_len', argument 1 of
>         type 'pyramid::MidiBytes *'

This message is typical of a swig object whose __init__ method has not 
been called. (No later than today, I forgot to call the base.__init__ in 
a derived class. Maybe we should ask Swig for a better message)
See above for a hint. Hope this helps...


-- 
Amaury



More information about the Python-list mailing list