[C++-sig] problem with boost::python and pickling

Jakub Zytka kubol at kormoran.net
Fri Jul 2 15:42:26 CEST 2010


I've run into some problem i do not understand. Consider following example, 
which is a slightly modified pickle2.cpp from boost's libs/python/test/:

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/class.hpp>
#include <boost/python/tuple.hpp>
#include <boost/python/extract.hpp>

namespace boost_python_test {

struct dummy // my addition
{
};
   // A friendly class.
   class world
   {
     public:
       world(const std::string& country) : secret_number(0) {
         this->country = country;
       }
       world(dummy) {}; // my addition
       std::string greet() const { return "Hello from " + country + "!"; }
       std::string get_country() const { return country; }
       void set_secret_number(int number) { secret_number = number; }
       int get_secret_number() const { return secret_number; }
     private:
       std::string country;
       int secret_number;
   };

   struct world_pickle_suite : boost::python::pickle_suite
   {
     static
     boost::python::tuple
     getinitargs(const world& w)
     {
         using namespace boost::python;
         return make_tuple(dummy()); // change to use dummy instead of string
     }

     static
     boost::python::tuple
     getstate(const world& w)
     {
         using namespace boost::python;
         return make_tuple(w.get_secret_number());
     }

     static
     void
     setstate(world& w, boost::python::tuple state)
     {
         using namespace boost::python;

         	boost::python::object lenRes = state.attr("__len__")(); // old boost
	int const stateLen = boost::python::extract<int>(lenRes);
         if (stateLen != 1)
         {
           PyErr_SetObject(PyExc_ValueError,
                           ("expected 1-item tuple in call to __setstate__; got %s"
                            % state).ptr()
               );
           throw_error_already_set();
         }
         long number = extract<long>(state[0]);
         if (number != 42)
             w.set_secret_number(number);
     }
   };

}

BOOST_PYTHON_MODULE(pickle2_ext)
{
boost::python::class_< boost_python_test::dummy>( "dummy", boost::python::no_init );

     boost::python::class_<boost_python_test::world>(
         "world", boost::python::init<boost_python_test::dummy>())
         .def( boost::python::init< std::string const & >())
         .def("greet", &boost_python_test::world::greet)
         .def("get_secret_number", &boost_python_test::world::get_secret_number)
         .def("set_secret_number", &boost_python_test::world::set_secret_number)
         .def_pickle(boost_python_test::world_pickle_suite())
         ;
}

Code is compiled with gcc41, boost 1.33.1; compile options that might be relevant:
-pthread -fno-strict-aliasing -O0 -fno-inline -g0 -m64 -fPIC

then i use follwing test:
import pickle2_ext
import pickle

a = pickle2_ext.world("asd")
a.set_secret_number(54)
print a.get_secret_number()
pickle.dump(a, open('a.p', 'w'), pickle.HIGHEST_PROTOCOL)
r = pickle.load(open('a.p'))
print r.get_secret_number()

This test yields (python 2.4):
54
Traceback (most recent call last):
   File "test.py", line 7, in ?
     r = pickle.load(open('a.p'))
   File "/usr/lib64/python2.4/pickle.py", line 1390, in load
     return Unpickler(file).load()
   File "/usr/lib64/python2.4/pickle.py", line 872, in load
     dispatch[key](self)
   File "/usr/lib64/python2.4/pickle.py", line 1153, in load_reduce
     value = func(*args)
Boost.Python.ArgumentError: Python argument types in
     world.__init__(world, dummy)
did not match C++ signature:
     __init__(_object*, std::string)
     __init__(_object*, boost_python_test::dummy)

The original example, with std::string as a constructor parameter, works fine.
What do i miss?

regards,
Jakub Żytka


More information about the Cplusplus-sig mailing list