[Checkins] SVN: keas.pbpersist/trunk/src/keas/pbpersist/ Added tests of persistent references and fixed the code that failed the
Shane Hathaway
shane at hathawaymix.org
Wed Jan 21 21:02:56 EST 2009
Log message for revision 94916:
Added tests of persistent references and fixed the code that failed the
tests.
Changed:
U keas.pbpersist/trunk/src/keas/pbpersist/README.txt
U keas.pbpersist/trunk/src/keas/pbpersist/pbformat.py
-=-
Modified: keas.pbpersist/trunk/src/keas/pbpersist/README.txt
===================================================================
--- keas.pbpersist/trunk/src/keas/pbpersist/README.txt 2009-01-22 00:54:08 UTC (rev 94915)
+++ keas.pbpersist/trunk/src/keas/pbpersist/README.txt 2009-01-22 02:02:55 UTC (rev 94916)
@@ -7,15 +7,21 @@
its state in a protobuf instance.
>>> from keas.pbpersist.tests import PContact
- >>> pc = PContact()
- >>> pc.__getstate__()
+ >>> bob = PContact()
+
+Can't serialize it yet.
+
+ >>> bob.__getstate__()
Traceback (most recent call last):
...
EncodeError: Required field ContactPB.name is not set.
- >>> pc.name = u'Joe'
- >>> pc.__getstate__()
- ('\x08\x01\x12\x03Joe', {})
+Fill out the required fields, then verify we can serialize it.
+
+ >>> bob.name = u'Bob'
+ >>> bob.__getstate__()
+ ('\x08\x01\x12\x03Bob', {})
+
Register the protobuf serializer with ZODB.
>>> from keas.pbpersist.pbformat import register
@@ -29,17 +35,37 @@
>>> storage = DemoStorage()
>>> db = DB(storage)
>>> conn1 = db.open()
- >>> conn1.root()['contact'] = pc
+ >>> conn1.root()['bob'] = bob
>>> transaction.commit()
Read the PContact from another connection.
>>> conn2 = db.open()
- >>> pc2 = conn2.root()['contact']
- >>> pc2.name
- u'Joe'
+ >>> bob2 = conn2.root()['bob']
+ >>> bob2.name
+ u'Bob'
>>> conn2.close()
+Create another PContact and assign that contact to be a guardian for Bob.
+[Ed: I sure don't like the way we manage references right now. I'd much
+rather see "bob.guardians.add().target = alice", but that is not yet
+possible.]
+
+ >>> alice = PContact()
+ >>> alice.name = u'Alice'
+ >>> ref = bob.guardians.add()
+ >>> bob.protobuf_refs.set(ref, alice)
+ >>> transaction.commit()
+
+Find Alice through Bob in another connection.
+
+ >>> conn2 = db.open()
+ >>> bob2 = conn2.root()['bob']
+ >>> alice2 = bob2.protobuf_refs.get(bob2.guardians[0])
+ >>> alice2.name
+ u'Alice'
+ >>> conn2.close()
+
Close the object database.
>>> transaction.abort()
Modified: keas.pbpersist/trunk/src/keas/pbpersist/pbformat.py
===================================================================
--- keas.pbpersist/trunk/src/keas/pbpersist/pbformat.py 2009-01-22 00:54:08 UTC (rev 94915)
+++ keas.pbpersist/trunk/src/keas/pbpersist/pbformat.py 2009-01-22 02:02:55 UTC (rev 94916)
@@ -7,6 +7,7 @@
from ZODB.format import register_format
from ZODB.utils import p64, u64
from ZODB.POSException import POSError
+from ZODB.broken import find_global as default_find_global
from keas.pbstate.state import StateTuple
from keas.pbpersist.persistent_pb2 import ClassMetadata
@@ -26,53 +27,22 @@
res.MergeFromString(data[len(format_prefix):])
return res
-def read_class_meta(class_meta):
- """Return a ZODB formatted tuple given a ClassMetadata.
-
- This uses class metadata format #3 described by the
- ZODB.serialize docstring.
- """
- return (class_meta.module_name, class_meta.class_name), None
-
-def write_class_meta(class_meta, source):
- """Set attributes of a ClassMetadata from a source class metadata object.
-
- The source is in any of the formats described by the
- ZODB.serialize docstring.
- """
- if not isinstance(source, tuple):
- # source is in format #1
- class_meta.module_name = source.__module__
- class_meta.class_name = source.__name__
- else:
- klass, args = source
- if args is not None:
- # source is in format #2, 4, 6, or 7
- raise POSError(
- "ProtobufSerializer can not serialize classes "
- "using __getnewargs__ or __getinitargs__")
- if isinstance(klass, tuple):
- # source is in format #3
- class_meta.module_name, class_meta.class_name = klass
- else:
- # source is in format #5
- class_meta.module_name = klass.__module__
- class_meta.class_name = klass.__name__
-
-def read_reference(ref):
+def read_reference(ref, find_global):
"""Return a ZODB formatted reference given a Reference message."""
oid = p64(ref.zoid)
if ref.weak:
return ['w', (oid,)]
elif ref.database:
if ref.class_meta:
- cm = read_class_meta(ref.class_meta)
- return ['m', (ref.database, oid, cm)]
+ klass = find_global(
+ ref.class_meta.module_name, ref.class_meta.class_name)
+ return ['m', (ref.database, oid, klass)]
else:
return ['n', (ref.database, oid)]
elif ref.class_meta:
- cm = read_class_meta(ref.class_meta)
- return (oid, cm)
+ klass = find_global(
+ ref.class_meta.module_name, ref.class_meta.class_name)
+ return (oid, klass)
else:
return oid
@@ -88,7 +58,8 @@
def listPersistentReferences(self, data):
record = decode_record(data)
- return (read_reference(ref) for ref in record.references)
+ return (read_reference(ref, default_find_global)
+ for ref in record.references)
class ProtobufSerializer(object):
@@ -100,7 +71,7 @@
def dump(self, classmeta, state):
"""Serialize a persistent object as an ObjectRecord message."""
record = ObjectRecord()
- write_class_meta(record.class_meta, classmeta)
+ self.set_class(record.class_meta, classmeta)
record.state, refs = state
for refid, target in refs.iteritems():
@@ -116,6 +87,31 @@
return '%s%s' % (format_prefix, record.SerializeToString())
+ def set_class(self, class_meta, source):
+ """Set attributes of a ClassMetadata from a source class metadata.
+
+ The source is in any of the formats described by the
+ ZODB.serialize docstring.
+ """
+ if not isinstance(source, tuple):
+ # source is in format #1
+ class_meta.module_name = source.__module__
+ class_meta.class_name = source.__name__
+ else:
+ klass, args = source
+ if args is not None:
+ # source is in format #2, 4, 6, or 7
+ raise POSError(
+ "ProtobufSerializer can not serialize classes "
+ "using __getnewargs__ or __getinitargs__")
+ if isinstance(klass, tuple):
+ # source is in format #3
+ class_meta.module_name, class_meta.class_name = klass
+ else:
+ # source is in format #5
+ class_meta.module_name = klass.__module__
+ class_meta.class_name = klass.__name__
+
def add_reference(self, record, refid, p):
"""Add a reference to an ObjectRecord.
@@ -125,9 +121,9 @@
r = record.references.add()
r.refid = refid
oid = None
- cm = None
+ klass = None
if isinstance(p, tuple):
- oid, cm = p
+ oid, klass = p
elif isinstance(p, str):
oid = p
elif len(p) == 1:
@@ -137,7 +133,7 @@
else:
ref_type, args = p
if ref_type == 'm':
- r.database, oid, cm = args
+ r.database, oid, klass = args
elif ref_type == 'w':
(oid,) = args
r.weak = True
@@ -146,8 +142,9 @@
else:
raise POSError("Unknown reference type: %s" % repr(ref_type))
r.zoid = u64(oid)
- if cm is not None:
- write_class_meta(r.class_meta, cm)
+ if klass is not None:
+ r.class_meta.module_name = klass.__module__
+ r.class_meta.class_name = klass.__name__
class ProtobufDeserializer(object):
@@ -155,14 +152,18 @@
def __init__(self, persistent_load, find_global=None):
self.persistent_load = persistent_load
- self.find_global = find_global
+ if find_global is None:
+ self.find_global = default_find_global
+ else:
+ self.find_global = find_global
def getClassAndState(self, data):
record = decode_record(data)
- yield read_class_meta(record.class_meta)
+ cm = record.class_meta
+ yield (cm.module_name, cm.class_name), None
ref_dict = {}
for ref in record.references:
- zodb_ref = read_reference(ref)
+ zodb_ref = read_reference(ref, self.find_global)
target = self.persistent_load(zodb_ref)
ref_dict[ref.refid] = target
yield record.state, ref_dict
More information about the Checkins
mailing list