mirror of
https://github.com/boostorg/python.git
synced 2026-01-22 17:32:55 +00:00
added: pickle safety measures; bug fix: use bound_function::create()
[SVN r9399]
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
// Revision History:
|
||||
// Mar 03 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve)
|
||||
|
||||
#ifndef CLASS_WRAPPER_DWA101000_H_
|
||||
# define CLASS_WRAPPER_DWA101000_H_
|
||||
|
||||
@@ -24,6 +27,13 @@ class class_builder
|
||||
|
||||
~class_builder()
|
||||
{}
|
||||
|
||||
inline void dict_defines_state() {
|
||||
add(ref(BOOST_PYTHON_CONVERSION::to_python(1)), "__dict_defines_state__");
|
||||
}
|
||||
inline void getstate_manages_dict() {
|
||||
add(ref(BOOST_PYTHON_CONVERSION::to_python(1)), "__getstate_manages_dict__");
|
||||
}
|
||||
|
||||
// define constructors
|
||||
template <class signature>
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
//
|
||||
// The author gratefully acknowleges the support of Dragon Systems, Inc., in
|
||||
// producing this work.
|
||||
//
|
||||
// Revision History:
|
||||
// Mar 03 01 added: pickle safety measures (Ralf W. Grosse-Kunstleve)
|
||||
// Mar 03 01 bug fix: use bound_function::create() (instead of new bound_function)
|
||||
|
||||
#include <boost/python/classes.hpp>
|
||||
#include <boost/python/detail/functions.hpp>
|
||||
@@ -67,8 +71,7 @@ namespace {
|
||||
|
||||
ref global_class_reduce()
|
||||
{
|
||||
static ref result(detail::new_wrapped_function(class_reduce));
|
||||
return result;
|
||||
return ref(detail::new_wrapped_function(class_reduce));
|
||||
}
|
||||
|
||||
|
||||
@@ -93,17 +96,41 @@ namespace {
|
||||
ref getstate(PyObject_GetAttrString(obj, const_cast<char*>("__getstate__")),
|
||||
ref::null_ok);
|
||||
PyErr_Clear();
|
||||
|
||||
ref dict(PyObject_GetAttrString(obj, const_cast<char*>("__dict__")), ref::null_ok);
|
||||
PyErr_Clear();
|
||||
|
||||
if (getstate.get() != 0)
|
||||
{
|
||||
if (dict.get() != 0 && dictionary(dict).size() > 0)
|
||||
{
|
||||
ref getstate_manages_dict(PyObject_GetAttrString(instance_class.get(), const_cast<char*>("__getstate_manages_dict__")), ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (getstate_manages_dict.get() == 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Incomplete pickle support (__getstate_manages_dict__ not set)");
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
ref state = ref(PyEval_CallObject(getstate.get(), NULL));
|
||||
return tuple(instance_class, initargs, state);
|
||||
}
|
||||
|
||||
ref state(PyObject_GetAttrString(obj, const_cast<char*>("__dict__")), ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (state.get() != 0 && dictionary(state).size() > 0)
|
||||
if (getinitargs.get() == 0)
|
||||
{
|
||||
return tuple(instance_class, initargs, state);
|
||||
ref dict_defines_state(PyObject_GetAttrString(instance_class.get(), const_cast<char*>("__dict_defines_state__")), ref::null_ok);
|
||||
PyErr_Clear();
|
||||
if (dict_defines_state.get() == 0)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, "Incomplete pickle support (__dict_defines_state__ not set)");
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
|
||||
if (dict.get() != 0 && dictionary(dict).size() > 0)
|
||||
{
|
||||
return tuple(instance_class, initargs, dict);
|
||||
}
|
||||
|
||||
return tuple(instance_class, initargs);
|
||||
@@ -111,8 +138,7 @@ namespace {
|
||||
|
||||
ref global_instance_reduce()
|
||||
{
|
||||
static ref result(detail::new_wrapped_function(instance_reduce));
|
||||
return result;
|
||||
return ref(detail::new_wrapped_function(instance_reduce));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +203,7 @@ namespace detail {
|
||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
||||
{
|
||||
ref target(as_object(this), ref::increment_count);
|
||||
return new bound_function(target, global_class_reduce());
|
||||
return bound_function::create(target, global_class_reduce());
|
||||
}
|
||||
|
||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
||||
@@ -348,7 +374,7 @@ PyObject* instance::getattr(const char* name, bool use_special_function)
|
||||
|
||||
if (!BOOST_CSTD_::strcmp(name, "__reduce__"))
|
||||
{
|
||||
return new detail::bound_function(ref(this, ref::increment_count), global_instance_reduce());
|
||||
return detail::bound_function::create(ref(this, ref::increment_count), global_instance_reduce());
|
||||
}
|
||||
|
||||
ref local_attribute = m_name_space.get_item(string(name).reference());
|
||||
|
||||
@@ -239,6 +239,47 @@ Pickling tests:
|
||||
Hello from California! 42
|
||||
Hello from California! 0
|
||||
|
||||
Pickle safety measures:
|
||||
>>> r=Rational(3, 4)
|
||||
>>> r
|
||||
Rational(3, 4)
|
||||
>>> try: s=pickle.dumps(r)
|
||||
... except RuntimeError, err: print err[0]
|
||||
...
|
||||
Incomplete pickle support (__dict_defines_state__ not set)
|
||||
>>> class myrational(Rational):
|
||||
... __dict_defines_state__ = 1 # this is a lie but good enough for testing.
|
||||
...
|
||||
>>> r=myrational(3, 4)
|
||||
>>> r
|
||||
Rational(3, 4)
|
||||
>>> s=pickle.dumps(r)
|
||||
|
||||
>>> class myworld(world):
|
||||
... def __init__(self):
|
||||
... world.__init__(self, 'anywhere')
|
||||
... self.x = 1
|
||||
...
|
||||
>>> w = myworld()
|
||||
>>> w.greet()
|
||||
'Hello from anywhere!'
|
||||
>>> w.__dict__
|
||||
{'x': 1}
|
||||
>>> try: s=pickle.dumps(w)
|
||||
... except RuntimeError, err: print err[0]
|
||||
...
|
||||
Incomplete pickle support (__getstate_manages_dict__ not set)
|
||||
|
||||
>>> class myunsafeworld(myworld):
|
||||
... __getstate_manages_dict__ = 1 # this is a lie but good enough for testing.
|
||||
...
|
||||
>>> w = myunsafeworld()
|
||||
>>> w.greet()
|
||||
'Hello from anywhere!'
|
||||
>>> w.__dict__
|
||||
{'x': 1}
|
||||
>>> s=pickle.dumps(w)
|
||||
|
||||
Special member attributes. Tests courtesy of Barry Scott <barry@scottb.demon.co.uk>
|
||||
|
||||
>>> class DerivedFromFoo(Foo):
|
||||
|
||||
Reference in New Issue
Block a user