2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-23 17:52:17 +00:00

class_::enable_pickling() in publicized interface; tested with everything incl. VC6 and 7.0

[SVN r22254]
This commit is contained in:
Ralf W. Grosse-Kunstleve
2004-02-13 05:32:38 +00:00
parent 4a7686cd33
commit ae1584ff3c
9 changed files with 147 additions and 7 deletions

View File

@@ -281,6 +281,7 @@ namespace boost { namespace python
// pickle support
template <typename PickleSuite>
self& def_pickle(PickleSuite const&);
self& enable_pickling();
};
}}
</pre>
@@ -709,6 +710,23 @@ class_&amp; def_pickle(PickleSuite const&amp;);
checks.</dt>
</dl>
<br>
<pre>
class_&amp; enable_pickling();
</pre>
<dl class="function-semantics">
<dt><b>Requires:</b> n/a</dt>
<dt><b>Effects:</b> Defines the <code>__reduce__</code> method and
the <code>__safe_for_unpickling__</code> attribute.
<dt><b>Returns:</b> <code>*this</code></dt>
<dt><b>Rationale:</b> Light-weight alternative to
<code>def_pickle()</code>. Enables implementation of
<a href="pickle.html">pickle support</a> from Python.</dt>
</dl>
<br>
<h3><a name="bases-spec"></a>Class template

View File

@@ -281,13 +281,51 @@ is not empty.
</ul>
<hr>
<h2>Light-weight alternative: pickle support implemented in Python</h2>
&copy; Copyright Ralf W. Grosse-Kunstleve 20012-2002. Permission to copy,
<h3><a href="../../test/pickle4.cpp"><tt>pickle4.cpp</tt></a></h3>
The <tt>pickle4.cpp</tt> example demonstrates an alternative technique
for implementing pickle support. First we direct Boost.Python via
the <tt>class_::enable_pickling()</tt> member function to define only
the basic attributes required for pickling:
<pre>
class_&lt;world&gt;("world", args&lt;const std::string&amp;&gt;())
// ...
.enable_pickling()
// ...
</pre>
This enables the standard Python pickle interface as described
in the Python documentation. By &quot;injecting&quot; a
<tt>__getinitargs__</tt> method into the definition of the wrapped
class we make all instances pickleable:
<pre>
# import the wrapped world class
from pickle4_ext import world
# definition of __getinitargs__
def world_getinitargs(self):
return (self.get_country(),)
# now inject __getinitargs__ (Python is a dynamic language!)
world.__getinitargs__ = world_getinitargs
</pre>
See also the
<a href="../tutorial/doc/extending_wrapped_objects_in_python.html"
>tutorial section</a> on injecting additional methods from Python.
<hr>
&copy; Copyright Ralf W. Grosse-Kunstleve 2001-2004. Permission to copy,
use, modify, sell and distribute this document is granted provided this
copyright notice appears in all copies. This document is provided "as
is" without express or implied warranty, and with no claim as to its
suitability for any purpose.
<p>
Updated: Aug 2002.
Updated: Feb 2004.
</div>

View File

@@ -415,6 +415,12 @@ class class_ : public objects::class_base
return *this;
}
self& enable_pickling()
{
this->base::enable_pickling_(false);
return *this;
}
self& staticmethod(char const* name)
{
this->make_method_static(name);

View File

@@ -32,7 +32,7 @@ struct BOOST_PYTHON_DECL class_base : python::api::object
// Implementation detail. Hiding this in the private section would
// require use of template friend declarations.
void enable_pickling(bool getstate_manages_dict);
void enable_pickling_(bool getstate_manages_dict);
protected:
void add_property(char const* name, object const& fget);

View File

@@ -59,7 +59,7 @@ namespace detail {
inaccessible* (*setstate_fn)(),
bool)
{
cl.enable_pickling(false);
cl.enable_pickling_(false);
cl.def("__getinitargs__", getinitargs_fn);
}
@@ -75,7 +75,7 @@ namespace detail {
void (*setstate_fn)(Tsetstate, Ttuple),
bool getstate_manages_dict)
{
cl.enable_pickling(getstate_manages_dict);
cl.enable_pickling_(getstate_manages_dict);
cl.def("__getstate__", getstate_fn);
cl.def("__setstate__", setstate_fn);
}
@@ -93,7 +93,7 @@ namespace detail {
void (*setstate_fn)(Tsetstate, Ttuple),
bool getstate_manages_dict)
{
cl.enable_pickling(getstate_manages_dict);
cl.enable_pickling_(getstate_manages_dict);
cl.def("__getinitargs__", getinitargs_fn);
cl.def("__getstate__", getstate_fn);
cl.def("__setstate__", setstate_fn);

View File

@@ -599,7 +599,7 @@ namespace objects
this->setattr("__init__", object(f));
}
void class_base::enable_pickling(bool getstate_manages_dict)
void class_base::enable_pickling_(bool getstate_manages_dict)
{
setattr("__reduce__", object(make_instance_reduce_function()));
setattr("__safe_for_unpickling__", object(true));

View File

@@ -151,6 +151,7 @@ bpl-test crossmod_exception
[ bpl-test pickle1 ]
[ bpl-test pickle2 ]
[ bpl-test pickle3 ]
[ bpl-test pickle4 ]
[ bpl-test nested ]

41
test/pickle4.cpp Normal file
View File

@@ -0,0 +1,41 @@
// Example by Ralf W. Grosse-Kunstleve
/*
This example shows how to enable pickling without using the
pickle_suite. The pickling interface (__getinitargs__) is
implemented in Python.
For more information refer to boost/libs/python/doc/pickle.html.
*/
#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <string>
namespace {
// A friendly class.
class world
{
private:
std::string country;
public:
world(const std::string& country) {
this->country = country;
}
std::string greet() const { return "Hello from " + country + "!"; }
std::string get_country() const { return country; }
};
}
BOOST_PYTHON_MODULE(pickle4_ext)
{
using namespace boost::python;
class_<world>("world", init<const std::string&>())
.enable_pickling()
.def("greet", &world::greet)
.def("get_country", &world::get_country)
;
}

36
test/pickle4.py Normal file
View File

@@ -0,0 +1,36 @@
r'''>>> import pickle4_ext
>>> import pickle
>>> def world_getinitargs(self):
... return (self.get_country(),)
>>> pickle4_ext.world.__getinitargs__ = world_getinitargs
>>> pickle4_ext.world.__module__
'pickle4_ext'
>>> pickle4_ext.world.__safe_for_unpickling__
1
>>> pickle4_ext.world.__name__
'world'
>>> pickle4_ext.world('Hello').__reduce__()
(<class 'pickle4_ext.world'>, ('Hello',))
>>> wd = pickle4_ext.world('California')
>>> pstr = pickle.dumps(wd)
>>> wl = pickle.loads(pstr)
>>> print wd.greet()
Hello from California!
>>> print wl.greet()
Hello from California!
'''
def run(args = None):
import sys
import doctest
if args is not None:
sys.argv = args
return doctest.testmod(sys.modules.get(__name__))
if __name__ == '__main__':
print "running..."
import sys
status = run()[0]
if (status == 0): print "Done."
sys.exit(status)