Commit 6418e314 authored by Hanno Schlichting's avatar Hanno Schlichting

Backport getnewargs fix from trunk

parent 31af907b
......@@ -4,6 +4,17 @@ Changelog
2.11.3 (unreleased)
-------------------
- Give both wrapper classes a ``__getnewargs__`` method, which causes the ZODB
optimization to fail and create persistent references using the ``_p_oid``
alone. This happens to be the persistent oid of the wrapped object. This lets
these objects to be persisted correctly, even though they are passed to the
ZODB in a wrapped state.
- Added failing tests for http://dev.plone.org/plone/ticket/10318. This shows
an edge-case where AQ wrappers can be pickled using the specific combination
of cPickle, pickle protocol one and a custom Pickler class with an
``inst_persistent_id`` hook. Unfortunately this is the exact combination used
by ZODB3.
2.11.2 (2010-02-25)
-------------------
......
......@@ -1206,6 +1206,12 @@ Wrappers_are_not_picklable(PyObject *wrapper, PyObject *args)
return NULL;
}
static PyObject *
Wrapper___getnewargs__(PyObject *self)
{
return PyTuple_New(0);
}
static struct PyMethodDef Wrapper_methods[] = {
{"acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
......@@ -1215,6 +1221,8 @@ static struct PyMethodDef Wrapper_methods[] = {
"Get an attribute, acquiring it if necessary"},
{"aq_inContextOf", (PyCFunction)Wrapper_inContextOf, METH_VARARGS,
"Test whether the object is currently in the context of the argument"},
{"__getnewargs__", (PyCFunction)Wrapper___getnewargs__, METH_NOARGS,
"Get arguments to be passed to __new__"},
{"__getstate__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
"Wrappers are not picklable"},
{"__reduce__", (PyCFunction)Wrappers_are_not_picklable, METH_VARARGS,
......
......@@ -1502,7 +1502,126 @@ def test_cant_pickle_acquisition_wrappers_newstyle():
TypeError: Can't pickle objects in acquisition wrappers.
"""
def test_z3interfaces():
def test_cant_persist_acquisition_wrappers_classic():
"""
>>> import cPickle
>>> class X:
... _p_oid = '1234'
... def __getstate__(self):
... return 1
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> w = ImplicitAcquisitionWrapper(X(), X())
>>> cPickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check for pickle protocol one:
>>> cPickle.dumps(w, 1)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check custom pickler:
>>> from cStringIO import StringIO
>>> file = StringIO()
>>> pickler = cPickle.Pickler(file, 1)
>>> pickler.dump(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check custom pickler with a persistent_id method matching the semantics
in ZODB.serialize.ObjectWriter.persistent_id:
>>> file = StringIO()
>>> pickler = cPickle.Pickler(file, 1)
>>> def persistent_id(obj):
... klass = type(obj)
... oid = obj._p_oid
... if hasattr(klass, '__getnewargs__'):
... return oid
... return 'class_and_oid', klass
>>> pickler.inst_persistent_id = persistent_id
>>> _ = pickler.dump(w)
>>> state = file.getvalue()
>>> '1234' in state
True
>>> 'class_and_oid' in state
False
"""
def test_cant_persist_acquisition_wrappers_newstyle():
"""
>>> import cPickle
>>> class X(object):
... _p_oid = '1234'
... def __getstate__(self):
... return 1
We shouldn't be able to pickle wrappers:
>>> from Acquisition import ImplicitAcquisitionWrapper
>>> w = ImplicitAcquisitionWrapper(X(), X())
>>> cPickle.dumps(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check for pickle protocol one:
>>> cPickle.dumps(w, 1)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check custom pickler:
>>> from cStringIO import StringIO
>>> file = StringIO()
>>> pickler = cPickle.Pickler(file, 1)
>>> pickler.dump(w)
Traceback (most recent call last):
...
TypeError: Can't pickle objects in acquisition wrappers.
Check custom pickler with a persistent_id method matching the semantics
in ZODB.serialize.ObjectWriter.persistent_id:
>>> file = StringIO()
>>> pickler = cPickle.Pickler(file, 1)
>>> def persistent_id(obj):
... klass = type(obj)
... oid = obj._p_oid
... if hasattr(klass, '__getnewargs__'):
... return oid
... return 'class_and_oid', klass
>>> pickler.inst_persistent_id = persistent_id
>>> _ = pickler.dump(w)
>>> state = file.getvalue()
>>> '1234' in state
True
>>> 'class_and_oid' in state
False
"""
def test_interfaces():
"""
>>> from zope.interface.verify import verifyClass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment