Skip to content

Commit ae1584f

Browse files
author
Ralf W. Grosse-Kunstleve
committed
class_::enable_pickling() in publicized interface; tested with everything incl. VC6 and 7.0
[SVN r22254]
1 parent 4a7686c commit ae1584f

File tree

9 files changed

+147
-7
lines changed

9 files changed

+147
-7
lines changed

doc/v2/class.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ <h4><a name="class_-spec-synopsis"></a>Class template <code>class_</code>
281281
// pickle support
282282
template &lt;typename PickleSuite&gt;
283283
self&amp; def_pickle(PickleSuite const&amp;);
284+
self&amp; enable_pickling();
284285
};
285286
}}
286287
</pre>
@@ -709,6 +710,23 @@ <h4><a name="class_-spec-modifiers"></a>Class template
709710
checks.</dt>
710711
</dl>
711712
<br>
713+
<pre>
714+
class_&amp; enable_pickling();
715+
</pre>
716+
717+
<dl class="function-semantics">
718+
<dt><b>Requires:</b> n/a</dt>
719+
720+
<dt><b>Effects:</b> Defines the <code>__reduce__</code> method and
721+
the <code>__safe_for_unpickling__</code> attribute.
722+
723+
<dt><b>Returns:</b> <code>*this</code></dt>
724+
725+
<dt><b>Rationale:</b> Light-weight alternative to
726+
<code>def_pickle()</code>. Enables implementation of
727+
<a href="pickle.html">pickle support</a> from Python.</dt>
728+
</dl>
729+
<br>
712730

713731

714732
<h3><a name="bases-spec"></a>Class template

doc/v2/pickle.html

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,51 @@ <h2>Practical Advice</h2>
281281
</ul>
282282

283283
<hr>
284+
<h2>Light-weight alternative: pickle support implemented in Python</h2>
284285

285-
&copy; Copyright Ralf W. Grosse-Kunstleve 20012-2002. Permission to copy,
286+
<h3><a href="../../test/pickle4.cpp"><tt>pickle4.cpp</tt></a></h3>
287+
288+
The <tt>pickle4.cpp</tt> example demonstrates an alternative technique
289+
for implementing pickle support. First we direct Boost.Python via
290+
the <tt>class_::enable_pickling()</tt> member function to define only
291+
the basic attributes required for pickling:
292+
293+
<pre>
294+
class_&lt;world&gt;("world", args&lt;const std::string&amp;&gt;())
295+
// ...
296+
.enable_pickling()
297+
// ...
298+
</pre>
299+
300+
This enables the standard Python pickle interface as described
301+
in the Python documentation. By &quot;injecting&quot; a
302+
<tt>__getinitargs__</tt> method into the definition of the wrapped
303+
class we make all instances pickleable:
304+
305+
<pre>
306+
# import the wrapped world class
307+
from pickle4_ext import world
308+
309+
# definition of __getinitargs__
310+
def world_getinitargs(self):
311+
return (self.get_country(),)
312+
313+
# now inject __getinitargs__ (Python is a dynamic language!)
314+
world.__getinitargs__ = world_getinitargs
315+
</pre>
316+
317+
See also the
318+
<a href="../tutorial/doc/extending_wrapped_objects_in_python.html"
319+
>tutorial section</a> on injecting additional methods from Python.
320+
321+
<hr>
322+
323+
&copy; Copyright Ralf W. Grosse-Kunstleve 2001-2004. Permission to copy,
286324
use, modify, sell and distribute this document is granted provided this
287325
copyright notice appears in all copies. This document is provided "as
288326
is" without express or implied warranty, and with no claim as to its
289327
suitability for any purpose.
290328

291329
<p>
292-
Updated: Aug 2002.
330+
Updated: Feb 2004.
293331
</div>

include/boost/python/class.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,12 @@ class class_ : public objects::class_base
415415
return *this;
416416
}
417417

418+
self& enable_pickling()
419+
{
420+
this->base::enable_pickling_(false);
421+
return *this;
422+
}
423+
418424
self& staticmethod(char const* name)
419425
{
420426
this->make_method_static(name);

include/boost/python/object/class.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
3232

3333
// Implementation detail. Hiding this in the private section would
3434
// require use of template friend declarations.
35-
void enable_pickling(bool getstate_manages_dict);
35+
void enable_pickling_(bool getstate_manages_dict);
3636

3737
protected:
3838
void add_property(char const* name, object const& fget);

include/boost/python/object/pickle_support.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ namespace detail {
5959
inaccessible* (*setstate_fn)(),
6060
bool)
6161
{
62-
cl.enable_pickling(false);
62+
cl.enable_pickling_(false);
6363
cl.def("__getinitargs__", getinitargs_fn);
6464
}
6565

@@ -75,7 +75,7 @@ namespace detail {
7575
void (*setstate_fn)(Tsetstate, Ttuple),
7676
bool getstate_manages_dict)
7777
{
78-
cl.enable_pickling(getstate_manages_dict);
78+
cl.enable_pickling_(getstate_manages_dict);
7979
cl.def("__getstate__", getstate_fn);
8080
cl.def("__setstate__", setstate_fn);
8181
}
@@ -93,7 +93,7 @@ namespace detail {
9393
void (*setstate_fn)(Tsetstate, Ttuple),
9494
bool getstate_manages_dict)
9595
{
96-
cl.enable_pickling(getstate_manages_dict);
96+
cl.enable_pickling_(getstate_manages_dict);
9797
cl.def("__getinitargs__", getinitargs_fn);
9898
cl.def("__getstate__", getstate_fn);
9999
cl.def("__setstate__", setstate_fn);

src/object/class.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ namespace objects
599599
this->setattr("__init__", object(f));
600600
}
601601

602-
void class_base::enable_pickling(bool getstate_manages_dict)
602+
void class_base::enable_pickling_(bool getstate_manages_dict)
603603
{
604604
setattr("__reduce__", object(make_instance_reduce_function()));
605605
setattr("__safe_for_unpickling__", object(true));

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ bpl-test crossmod_exception
151151
[ bpl-test pickle1 ]
152152
[ bpl-test pickle2 ]
153153
[ bpl-test pickle3 ]
154+
[ bpl-test pickle4 ]
154155

155156
[ bpl-test nested ]
156157

test/pickle4.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Example by Ralf W. Grosse-Kunstleve
2+
3+
/*
4+
This example shows how to enable pickling without using the
5+
pickle_suite. The pickling interface (__getinitargs__) is
6+
implemented in Python.
7+
8+
For more information refer to boost/libs/python/doc/pickle.html.
9+
*/
10+
11+
#include <boost/python/module.hpp>
12+
#include <boost/python/class.hpp>
13+
14+
#include <string>
15+
16+
namespace {
17+
18+
// A friendly class.
19+
class world
20+
{
21+
private:
22+
std::string country;
23+
public:
24+
world(const std::string& country) {
25+
this->country = country;
26+
}
27+
std::string greet() const { return "Hello from " + country + "!"; }
28+
std::string get_country() const { return country; }
29+
};
30+
31+
}
32+
33+
BOOST_PYTHON_MODULE(pickle4_ext)
34+
{
35+
using namespace boost::python;
36+
class_<world>("world", init<const std::string&>())
37+
.enable_pickling()
38+
.def("greet", &world::greet)
39+
.def("get_country", &world::get_country)
40+
;
41+
}

test/pickle4.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
r'''>>> import pickle4_ext
2+
>>> import pickle
3+
>>> def world_getinitargs(self):
4+
... return (self.get_country(),)
5+
>>> pickle4_ext.world.__getinitargs__ = world_getinitargs
6+
>>> pickle4_ext.world.__module__
7+
'pickle4_ext'
8+
>>> pickle4_ext.world.__safe_for_unpickling__
9+
1
10+
>>> pickle4_ext.world.__name__
11+
'world'
12+
>>> pickle4_ext.world('Hello').__reduce__()
13+
(<class 'pickle4_ext.world'>, ('Hello',))
14+
>>> wd = pickle4_ext.world('California')
15+
>>> pstr = pickle.dumps(wd)
16+
>>> wl = pickle.loads(pstr)
17+
>>> print wd.greet()
18+
Hello from California!
19+
>>> print wl.greet()
20+
Hello from California!
21+
'''
22+
23+
def run(args = None):
24+
import sys
25+
import doctest
26+
27+
if args is not None:
28+
sys.argv = args
29+
return doctest.testmod(sys.modules.get(__name__))
30+
31+
if __name__ == '__main__':
32+
print "running..."
33+
import sys
34+
status = run()[0]
35+
if (status == 0): print "Done."
36+
sys.exit(status)

0 commit comments

Comments
 (0)