Commit f024924f authored by Tim Peters's avatar Tim Peters

Move the Persistence package, from ZODB trunk to Zope trunk.

parent 116f06f6
/*
Copyright (c) 2003 Zope Corporation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE.
*/
static char _Persistence_module_documentation[] =
"Persistent ExtensionClass\n"
"\n"
"$Id$\n"
;
#include "ExtensionClass.h"
#include "cPersistence.h"
/* convert_name() returns a new reference to a string name
or sets an exception and returns NULL.
*/
static PyObject *
convert_name(PyObject *name)
{
#ifdef Py_USING_UNICODE
/* The Unicode to string conversion is done here because the
existing tp_setattro slots expect a string object as name
and we wouldn't want to break those. */
if (PyUnicode_Check(name)) {
name = PyUnicode_AsEncodedString(name, NULL, NULL);
}
else
#endif
if (!PyString_Check(name)) {
PyErr_SetString(PyExc_TypeError, "attribute name must be a string");
return NULL;
} else
Py_INCREF(name);
return name;
}
/* Returns true if the object requires unghostification.
There are several special attributes that we allow access to without
requiring that the object be unghostified:
__class__
__del__
__dict__
__of__
__setstate__
*/
static int
unghost_getattr(const char *s)
{
if (*s++ != '_')
return 1;
if (*s == 'p') {
s++;
if (*s == '_')
return 0; /* _p_ */
else
return 1;
}
else if (*s == '_') {
s++;
switch (*s) {
case 'c':
return strcmp(s, "class__");
case 'd':
s++;
if (!strcmp(s, "el__"))
return 0; /* __del__ */
if (!strcmp(s, "ict__"))
return 0; /* __dict__ */
return 1;
case 'o':
return strcmp(s, "of__");
case 's':
return strcmp(s, "setstate__");
default:
return 1;
}
}
return 1;
}
static PyObject *
P_getattr(cPersistentObject *self, PyObject *name)
{
PyObject *v=NULL;
char *s;
name = convert_name(name);
if (!name)
return NULL;
s = PyString_AS_STRING(name);
if (*s != '_' || unghost_getattr(s))
{
if (PER_USE(self))
{
v = Py_FindAttr((PyObject*)self, name);
PER_ALLOW_DEACTIVATION(self);
PER_ACCESSED(self);
}
}
else
v = Py_FindAttr((PyObject*)self, name);
Py_DECREF(name);
return v;
}
static PyTypeObject Ptype = {
PyObject_HEAD_INIT(NULL)
/* ob_size */ 0,
/* tp_name */ "Persistence.Persistent",
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* tp_getattro */ (getattrofunc)P_getattr,
0, 0,
/* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE ,
/* tp_doc */ "Persistent ExtensionClass",
};
static struct PyMethodDef _Persistence_methods[] = {
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
init_Persistence(void)
{
PyObject *m;
if (! ExtensionClassImported)
return;
cPersistenceCAPI = PyCObject_Import("persistent.cPersistence", "CAPI");
if (cPersistenceCAPI == NULL)
return;
Ptype.tp_bases = Py_BuildValue("OO", cPersistenceCAPI->pertype, ECBaseType);
if (Ptype.tp_bases == NULL)
return;
Ptype.tp_base = cPersistenceCAPI->pertype;
Ptype.ob_type = ECExtensionClassType;
if (PyType_Ready(&Ptype) < 0)
return;
/* Create the module and add the functions */
m = Py_InitModule3("_Persistence", _Persistence_methods,
_Persistence_module_documentation);
if (m == NULL)
return;
/* Add types: */
if (PyModule_AddObject(m, "Persistent", (PyObject *)&Ptype) < 0)
return;
}
##############################################################################
#
# Copyright (c) 2001, 2002, 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Persistence and ExtensionClass combined
$Id$
"""
from persistent import PickleCache
try:
from _Persistence import Persistent
except:
from warnings import warn
warn("""Couldn't import the ExtensionClass-based base class
There are two possibilities:
1. You don't care about ExtensionClass. You are importing
Persistence because that's what you imported in the past.
In this case, you should really use the persistent package
instead:
>>> from persistent import Persistent
>>> from persistent.list import PersistentList
>>> from persistent.mapping import PersistentMapping
2. You want your classes to be ExtensionClasses. In this case,
you need to install the ExtensionClass package
separately. ExtensionClass is no-longer included with ZODB3.
""")
from persistent import Persistent
Overridable = Persistent
from Persistence.mapping import PersistentMapping
# This is a travesty. Whimper. The Data.fs.in used in Zope 2 have
# ancient pickles refering to BoboPOS. Waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
import sys
sys.modules['BoboPOS'] = sys.modules['Persistence']
sys.modules['BoboPOS.PersistentMapping'] = sys.modules['Persistence.mapping']
del sys
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Python implementation of persistent base types
$Id$"""
import Persistence
import persistent
from persistent.mapping import PersistentMapping
if Persistence.Persistent is not persistent.Persistent:
class PersistentMapping(Persistence.Persistent, PersistentMapping):
"""Legacy persistent mapping class
This class mixes in ExtensionClass Base if it is present.
Unless you actually want ExtensionClass semantics, use
persistent.mapping.PersistentMapping instead.
"""
def __setstate__(self, state):
if 'data' not in state:
state['data'] = state['_container']
del state['_container']
self.__dict__.update(state)
#############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
import pickle
import time
import unittest
from Persistence import Persistent
from persistent.cPickleCache import PickleCache
from persistent.TimeStamp import TimeStamp
from ZODB.utils import p64
class Jar(object):
"""Testing stub for _p_jar attribute."""
def __init__(self):
self.cache = PickleCache(self)
self.oid = 1
self.registered = {}
def add(self, obj):
obj._p_oid = p64(self.oid)
self.oid += 1
obj._p_jar = self
self.cache[obj._p_oid] = obj
def close(self):
pass
# the following methods must be implemented to be a jar
def setklassstate(self):
# I don't know what this method does, but the pickle cache
# constructor calls it.
pass
def register(self, obj):
self.registered[obj] = 1
def setstate(self, obj):
# Trivial setstate() implementation that just re-initializes
# the object. This isn't what setstate() is supposed to do,
# but it suffices for the tests.
obj.__class__.__init__(obj)
class P(Persistent):
pass
class H1(Persistent):
def __init__(self):
self.n = 0
def __getattr__(self, attr):
self.n += 1
return self.n
class H2(Persistent):
def __init__(self):
self.n = 0
def __getattribute__(self, attr):
supergetattr = super(H2, self).__getattribute__
try:
return supergetattr(attr)
except AttributeError:
n = supergetattr("n")
self.n = n + 1
return n + 1
class PersistenceTest(unittest.TestCase):
def setUp(self):
self.jar = Jar()
def tearDown(self):
self.jar.close()
def testOidAndJarAttrs(self):
obj = P()
self.assertEqual(obj._p_oid, None)
obj._p_oid = 12
self.assertEqual(obj._p_oid, 12)
del obj._p_oid
self.jar.add(obj)
# Can't change oid of cache object.
def deloid():
del obj._p_oid
self.assertRaises(ValueError, deloid)
def setoid():
obj._p_oid = 12
self.assertRaises(ValueError, setoid)
def deloid():
del obj._p_jar
self.assertRaises(ValueError, deloid)
def setoid():
obj._p_jar = 12
self.assertRaises(ValueError, setoid)
def testChanged(self):
obj = P()
self.jar.add(obj)
# The value returned for _p_changed can be one of:
# 0 -- it is not changed
# 1 -- it is changed
# None -- it is a ghost
obj.x = 1
self.assertEqual(obj._p_changed, 1)
self.assert_(obj in self.jar.registered)
obj._p_changed = 0
self.assertEqual(obj._p_changed, 0)
self.jar.registered.clear()
obj._p_changed = 1
self.assertEqual(obj._p_changed, 1)
self.assert_(obj in self.jar.registered)
# setting obj._p_changed to None ghostifies if the
# object is in the up-to-date state, but not otherwise.
obj._p_changed = None
self.assertEqual(obj._p_changed, 1)
obj._p_changed = 0
# Now it's a ghost.
obj._p_changed = None
self.assertEqual(obj._p_changed, None)
obj = P()
self.jar.add(obj)
obj._p_changed = 1
# You can transition directly from modified to ghost if
# you delete the _p_changed attribute.
del obj._p_changed
self.assertEqual(obj._p_changed, None)
def testSerial(self):
noserial = "\000" * 8
obj = P()
self.assertEqual(obj._p_serial, noserial)
def set(val):
obj._p_serial = val
self.assertRaises(ValueError, set, 1)
self.assertRaises(ValueError, set, "0123")
self.assertRaises(ValueError, set, "012345678")
self.assertRaises(ValueError, set, u"01234567")
obj._p_serial = "01234567"
del obj._p_serial
self.assertEqual(obj._p_serial, noserial)
def testMTime(self):
obj = P()
self.assertEqual(obj._p_mtime, None)
t = int(time.time())
ts = TimeStamp(*time.gmtime(t)[:6])
obj._p_serial = repr(ts)
self.assertEqual(obj._p_mtime, t)
self.assert_(isinstance(obj._p_mtime, float))
def testPicklable(self):
obj = P()
obj.attr = "test"
s = pickle.dumps(obj)
obj2 = pickle.loads(s)
self.assertEqual(obj.attr, obj2.attr)
def testGetattr(self):
obj = H1()
self.assertEqual(obj.larry, 1)
self.assertEqual(obj.curly, 2)
self.assertEqual(obj.moe, 3)
self.jar.add(obj)
obj._p_deactivate()
# The simple Jar used for testing re-initializes the object.
self.assertEqual(obj.larry, 1)
# The getattr hook modified the object, so it should now be
# in the changed state.
self.assertEqual(obj._p_changed, 1)
self.assertEqual(obj.curly, 2)
self.assertEqual(obj.moe, 3)
def testGetattribute(self):
obj = H2()
self.assertEqual(obj.larry, 1)
self.assertEqual(obj.curly, 2)
self.assertEqual(obj.moe, 3)
self.jar.add(obj)
obj._p_deactivate()
# The simple Jar used for testing re-initializes the object.
self.assertEqual(obj.larry, 1)
# The getattr hook modified the object, so it should now be
# in the changed state.
self.assertEqual(obj._p_changed, 1)
self.assertEqual(obj.curly, 2)
self.assertEqual(obj.moe, 3)
# TODO: Need to decide how __setattr__ and __delattr__ should work,
# then write tests.
def test_suite():
return unittest.makeSuite(PersistenceTest)
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test ExtensionClass support in Persistence.Persistent
$Id$
"""
from zope.testing.doctest import DocTestSuite
import pickle
from Persistence import Persistent
try:
# The _Persistence module is only compiled in a Zope checkout,
# where ExtensionClass is available.
import Persistence._Persistence
except ImportError:
pass
else:
def test_basic():
"""
>>> from ExtensionClass import Base
- Support for a class initialiser:
>>> class C(Persistent):
... def __class_init__(self):
... print 'class init called'
... print self.__name__
... def bar(self):
... return 'bar called'
class init called
C
>>> c = C()
>>> int(c.__class__ is C)
1
>>> int(c.__class__ is type(c))
1
- Provide an inheritedAttribute method for looking up attributes in
base classes:
>>> class C2(C):
... def bar(*a):
... return C2.inheritedAttribute('bar')(*a), 42
class init called
C2
>>> o = C2()
>>> o.bar()
('bar called', 42)
This is for compatability with old code. New code should use super
instead.
The base class, Base, exists mainly to support the __of__ protocol.
The __of__ protocol is similar to __get__ except that __of__ is called
when an implementor is retrieved from an instance as well as from a
class:
>>> class O(Base):
... def __of__(*a):
... return a
>>> o1 = O()
>>> o2 = O()
>>> C.o1 = o1
>>> c.o2 = o2
>>> c.o1 == (o1, c)
1
>>> C.o1 == o1
1
>>> int(c.o2 == (o2, c))
1
We accomplish this by making a class that implements __of__ a
descriptor and treating all descriptor ExtensionClasses this way. That
is, if an extension class is a descriptor, it's __get__ method will be
called even when it is retrieved from an instance.
>>> class O(Base):
... def __get__(*a):
... return a
...
>>> o1 = O()
>>> o2 = O()
>>> C.o1 = o1
>>> c.o2 = o2
>>> int(c.o1 == (o1, c, type(c)))
1
>>> int(C.o1 == (o1, None, type(c)))
1
>>> int(c.o2 == (o2, c, type(c)))
1
"""
def test_mixing():
"""Test working with a classic class
>>> class Classic:
... def x(self):
... return 42
>>> class O(Persistent):
... def __of__(*a):
... return a
>>> class O2(Classic, O):
... def __of__(*a):
... return (O2.inheritedAttribute('__of__')(*a),
... O2.inheritedAttribute('x')(a[0]))
>>> class C(Persistent):
... def __class_init__(self):
... print 'class init called'
... print self.__name__
... def bar(self):
... return 'bar called'
class init called
C
>>> c = C()
>>> o2 = O2()
>>> c.o2 = o2
>>> int(c.o2 == ((o2, c), 42))
1
Test working with a new style
>>> class Modern(object):
... def x(self):
... return 42
>>> class O2(Modern, O):
... def __of__(*a):
... return (O2.inheritedAttribute('__of__')(*a),
... O2.inheritedAttribute('x')(a[0]))
>>> o2 = O2()
>>> c.o2 = o2
>>> int(c.o2 == ((o2, c), 42))
1
"""
def proper_error_on_deleattr():
"""
Florent Guillaume wrote:
...
Excellent.
Will it also fix this particularity of ExtensionClass:
>>> class A(Persistent):
... def foo(self):
... self.gee
... def bar(self):
... del self.gee
>>> a=A()
>>> a.foo()
Traceback (most recent call last):
...
AttributeError: gee
>>> a.bar()
Traceback (most recent call last):
...
AttributeError: 'A' object has no attribute 'gee'
I.e., the fact that KeyError is raised whereas a normal class would
raise AttributeError.
"""
def test__basicnew__():
"""
>>> x = Simple.__basicnew__()
>>> x.__dict__
{}
"""
def test_setattr_on_extension_type():
"""
>>> for name in 'x', '_x', 'x_', '__x_y__', '___x__', '__x___', '_x_':
... setattr(Persistent, name, 1)
... print getattr(Persistent, name)
... delattr(Persistent, name)
... print getattr(Persistent, name, 0)
1
0
1
0
1
0
1
0
1
0
1
0
1
0
>>> Persistent.__foo__ = 1
Traceback (most recent call last):
...
TypeError: can't set attributes of built-in/extension type """ \
"""'Persistence.Persistent' if the attribute name begins """ \
"""and ends with __ and contains only 4 _ characters
>>> Persistent.__foo__
Traceback (most recent call last):
...
AttributeError: type object 'Persistence.Persistent' """ \
"""has no attribute '__foo__'
>>> del Persistent.__foo__
Traceback (most recent call last):
...
TypeError: can't set attributes of built-in/extension type """ \
"""'Persistence.Persistent' if the attribute name begins """ \
"""and ends with __ and contains only 4 _ characters
"""
def test_class_creation_under_stress():
"""
>>> for i in range(100):
... class B(Persistent):
... print i,
... if i and i%20 == 0:
... print
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
>>> import gc
>>> x = gc.collect()
"""
def print_dict(d):
d = d.items()
d.sort()
print '{%s}' % (', '.join(
[('%r: %r' % (k, v)) for (k, v) in d]
))
def cmpattrs(self, other, *attrs):
for attr in attrs:
if attr[:3] in ('_v_', '_p_'):
continue
c = cmp(getattr(self, attr, None), getattr(other, attr, None))
if c:
return c
return 0
class Simple(Persistent):
def __init__(self, name, **kw):
self.__name__ = name
self.__dict__.update(kw)
self._v_favorite_color = 'blue'
self._p_foo = 'bar'
def __cmp__(self, other):
return cmpattrs(self, other, '__class__', *(self.__dict__.keys()))
def test_basic_pickling():
"""
>>> x = Simple('x', aaa=1, bbb='foo')
>>> print_dict(x.__getstate__())
{'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
>>> f, (c,), state = x.__reduce__()
>>> f.__name__
'__newobj__'
>>> f.__module__
'copy_reg'
>>> c.__name__
'Simple'
>>> print_dict(state)
{'__name__': 'x', 'aaa': 1, 'bbb': 'foo'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
>>> x.__setstate__({'z': 1})
>>> x.__dict__
{'z': 1}
"""
class Custom(Simple):
def __new__(cls, x, y):
r = Persistent.__new__(cls)
r.x, r.y = x, y
return r
def __init__(self, x, y):
self.a = 42
def __getnewargs__(self):
return self.x, self.y
def __getstate__(self):
return self.a
def __setstate__(self, a):
self.a = a
def test_pickling_w_overrides():
"""
>>> x = Custom('x', 'y')
>>> x.a = 99
>>> (f, (c, ax, ay), a) = x.__reduce__()
>>> f.__name__
'__newobj__'
>>> f.__module__
'copy_reg'
>>> c.__name__
'Custom'
>>> ax, ay, a
('x', 'y', 99)
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
"""
class Slotted(Persistent):
__slots__ = 's1', 's2', '_p_splat', '_v_eek'
def __init__(self, s1, s2):
self.s1, self.s2 = s1, s2
self._v_eek = 1
self._p_splat = 2
class SubSlotted(Slotted):
__slots__ = 's3', 's4'
def __init__(self, s1, s2, s3):
Slotted.__init__(self, s1, s2)
self.s3 = s3
def __cmp__(self, other):
return cmpattrs(self, other, '__class__', 's1', 's2', 's3', 's4')
def test_pickling_w_slots_only():
"""
>>> x = SubSlotted('x', 'y', 'z')
>>> d, s = x.__getstate__()
>>> d
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
>>> x.s4 = 'spam'
>>> d, s = x.__getstate__()
>>> d
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
"""
class SubSubSlotted(SubSlotted):
def __init__(self, s1, s2, s3, **kw):
SubSlotted.__init__(self, s1, s2, s3)
self.__dict__.update(kw)
self._v_favorite_color = 'blue'
self._p_foo = 'bar'
def __cmp__(self, other):
return cmpattrs(self, other,
'__class__', 's1', 's2', 's3', 's4',
*(self.__dict__.keys()))
def test_pickling_w_slots():
"""
>>> x = SubSubSlotted('x', 'y', 'z', aaa=1, bbb='foo')
>>> d, s = x.__getstate__()
>>> print_dict(d)
{'aaa': 1, 'bbb': 'foo'}
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
>>> x.s4 = 'spam'
>>> d, s = x.__getstate__()
>>> print_dict(d)
{'aaa': 1, 'bbb': 'foo'}
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
"""
def test_pickling_w_slots_w_empty_dict():
"""
>>> x = SubSubSlotted('x', 'y', 'z')
>>> d, s = x.__getstate__()
>>> print_dict(d)
{}
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
>>> x.s4 = 'spam'
>>> d, s = x.__getstate__()
>>> print_dict(d)
{}
>>> print_dict(s)
{'s1': 'x', 's2': 'y', 's3': 'z', 's4': 'spam'}
>>> pickle.loads(pickle.dumps(x)) == x
1
>>> pickle.loads(pickle.dumps(x, 0)) == x
1
>>> pickle.loads(pickle.dumps(x, 1)) == x
1
>>> pickle.loads(pickle.dumps(x, 2)) == x
1
"""
def test_suite():
return DocTestSuite()
##############################################################################
#
# Copyright (c) 2003 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
$Id$
"""
import unittest
from zope.testing.doctest import DocTestSuite
from Persistence import PersistentMapping
def test_basic_functionality():
"""
>>> m = PersistentMapping({'x': 1}, a=2, b=3)
>>> m['name'] = 'bob'
>>> m['fred']
Traceback (most recent call last):
...
KeyError: 'fred'
>>> m.get('fred')
>>> m.get('fred', 42)
42
>>> m.get('name', 42)
'bob'
>>> m.get('name')
'bob'
>>> m['name']
'bob'
>>> keys = m.keys()
>>> keys.sort()
>>> keys
['a', 'b', 'name', 'x']
>>> values = m.values()
>>> values.sort()
>>> values
[1, 2, 3, 'bob']
>>> items = m.items()
>>> items.sort()
>>> items
[('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)]
>>> keys = list(m.iterkeys())
>>> keys.sort()
>>> keys
['a', 'b', 'name', 'x']
>>> values = list(m.itervalues())
>>> values.sort()
>>> values
[1, 2, 3, 'bob']
>>> items = list(m.iteritems())
>>> items.sort()
>>> items
[('a', 2), ('b', 3), ('name', 'bob'), ('x', 1)]
>>> 'name' in m
True
"""
def test_old_pickles():
"""
>>> m = PersistentMapping()
>>> m.__setstate__({'_container': {'x': 1, 'y': 2}})
>>> items = m.items()
>>> items.sort()
>>> items
[('x', 1), ('y', 2)]
"""
def test_suite():
return unittest.TestSuite((
DocTestSuite(),
))
if __name__ == '__main__': unittest.main()
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