• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Ralf W. Grosse-Kunstleve 2002-2004. Distributed under the Boost
2 // Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4 
5 /*
6     This example shows how to make an Extension Class "pickleable".
7 
8     The world class below contains member data (secret_number) that
9     cannot be restored by any of the constructors. Therefore it is
10     necessary to provide the __getstate__/__setstate__ pair of pickle
11     interface methods.
12 
13     The object's __dict__ is included in the result of __getstate__.
14     This requires more code (compare with pickle2.cpp), but is
15     unavoidable if the object's __dict__ is not always empty.
16 
17     For more information refer to boost/libs/python/doc/pickle.html.
18  */
19 
20 #include <boost/python/module.hpp>
21 #include <boost/python/def.hpp>
22 #include <boost/python/class.hpp>
23 #include <boost/python/tuple.hpp>
24 #include <boost/python/dict.hpp>
25 #include <boost/python/extract.hpp>
26 #include <boost/python/back_reference.hpp>
27 
28 namespace boost_python_test {
29 
30   // A friendly class.
31   class world
32   {
33     public:
world(const std::string & _country)34       world(const std::string& _country) : secret_number(0) {
35         this->country = _country;
36       }
greet() const37       std::string greet() const { return "Hello from " + country + "!"; }
get_country() const38       std::string get_country() const { return country; }
set_secret_number(int number)39       void set_secret_number(int number) { secret_number = number; }
get_secret_number() const40       int get_secret_number() const { return secret_number; }
41     private:
42       std::string country;
43       int secret_number;
44   };
45 
46   struct world_pickle_suite : boost::python::pickle_suite
47   {
48     static
49     boost::python::tuple
getinitargsboost_python_test::world_pickle_suite50     getinitargs(const world& w)
51     {
52         return boost::python::make_tuple(w.get_country());
53     }
54 
55     static
56     boost::python::tuple
getstateboost_python_test::world_pickle_suite57     getstate(boost::python::object w_obj)
58     {
59         world const& w = boost::python::extract<world const&>(w_obj)();
60 
61         return boost::python::make_tuple(
62             w_obj.attr("__dict__"),
63             w.get_secret_number());
64     }
65 
66     static
67     void
setstateboost_python_test::world_pickle_suite68     setstate(boost::python::object w_obj, boost::python::tuple state)
69     {
70         using namespace boost::python;
71         world& w = extract<world&>(w_obj)();
72 
73         if (len(state) != 2)
74         {
75           PyErr_SetObject(PyExc_ValueError,
76                           ("expected 2-item tuple in call to __setstate__; got %s"
77                            % state).ptr()
78               );
79           throw_error_already_set();
80         }
81 
82         // restore the object's __dict__
83         dict d = extract<dict>(w_obj.attr("__dict__"))();
84         d.update(state[0]);
85 
86         // restore the internal state of the C++ object
87         long number = extract<long>(state[1]);
88         if (number != 42)
89             w.set_secret_number(number);
90     }
91 
getstate_manages_dictboost_python_test::world_pickle_suite92     static bool getstate_manages_dict() { return true; }
93   };
94 
95 }
96 
BOOST_PYTHON_MODULE(pickle3_ext)97 BOOST_PYTHON_MODULE(pickle3_ext)
98 {
99     using namespace boost_python_test;
100     boost::python::class_<world>(
101         "world", boost::python::init<const std::string&>())
102         .def("greet", &world::greet)
103         .def("get_secret_number", &world::get_secret_number)
104         .def("set_secret_number", &world::set_secret_number)
105         .def_pickle(world_pickle_suite())
106         ;
107 }
108