[Checkins] SVN: keas.pbstate/trunk/src/keas/pbstate/ Decided not to use subscript notation in a new way. It was too
Shane Hathaway
shane at hathawaymix.org
Tue Jan 13 01:52:15 EST 2009
Log message for revision 94718:
Decided not to use subscript notation in a new way. It was too
surprising.
Changed:
U keas.pbstate/trunk/src/keas/pbstate/README.txt
U keas.pbstate/trunk/src/keas/pbstate/meta.py
-=-
Modified: keas.pbstate/trunk/src/keas/pbstate/README.txt
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/README.txt 2009-01-13 06:35:09 UTC (rev 94717)
+++ keas.pbstate/trunk/src/keas/pbstate/README.txt 2009-01-13 06:52:15 UTC (rev 94718)
@@ -137,32 +137,28 @@
Object References
-----------------
-This library supports references to arbitrary objects through the use
-of an automatically generated reference identifier or "refid".
+Classes using the ProtobufState metaclass support references to arbitrary
+objects through the use of the 'protobuf_refs' attribute.
-Add a guardian to c2, but don't say who the guardian is yet.
+Add a guardian to c2, but don't say who the guardian is yet. Note that
+the .proto file defines the guardians list as a list of messages that
+have a _p_refid attribute.
>>> guardian_ref = c2.guardians.add()
-Using subscript notation on the protobuf_refs attribute, assign c to be
-a guardian of c2.
+Call protobuf_refs.set() to make guardian_ref refer to c.
- >>> c2.protobuf_refs[guardian_ref] = c
+ >>> c2.protobuf_refs.set(guardian_ref, c)
-Although this makes protobuf_refs look like a mapping, it does not behave
-like a mapping. Under the covers, a reference ID was generated, then that
+The set method generated a reference ID, then that
ID was assigned to guardian_ref._p_refid, and the refid and target object
-were added to the internal state of the protobuf_refs attribute. Any message
+were added to the internal state of the protobuf_refs instance. Any message
with a _p_refid field is a reference. Every _p_refid field should be
of type uint32.
-(Editor's note: I suspect this may be a significant abuse of subscript
-notation, so in the future this may be replaced with a less surprising
-interface.)
-
Read the reference.
- >>> c2.protobuf_refs[guardian_ref] is c
+ >>> c2.protobuf_refs.get(guardian_ref) is c
True
Verify the reference gets serialized correctly.
@@ -173,11 +169,9 @@
Delete the reference.
- >>> del c2.protobuf_refs[guardian_ref]
- >>> c2.protobuf_refs[guardian_ref]
- Traceback (most recent call last):
- ...
- KeyError: 'No reference set'
+ >>> c2.protobuf_refs.delete(guardian_ref)
+ >>> c2.protobuf_refs.get(guardian_ref, 'gone')
+ 'gone'
Verify the reference is no longer contained in the serialized state.
@@ -265,7 +259,7 @@
Synthesize a refid hash collision. First make a reference:
>>> guardian_ref = c2.guardians.add()
- >>> c2.protobuf_refs[guardian_ref] = c
+ >>> c2.protobuf_refs.set(guardian_ref, c)
Covertly change the target of that reference:
@@ -276,7 +270,7 @@
refid automatically.
>>> guardian2_ref = c2.guardians.add()
- >>> c2.protobuf_refs[guardian2_ref] = c
+ >>> c2.protobuf_refs.set(guardian2_ref, c)
>>> guardian_ref._p_refid == guardian2_ref._p_refid
False
@@ -306,16 +300,17 @@
AttributeError: Field 'bogus' not defined for protobuf type <...>
Create a broken reference by setting a reference using the wrong
-protobuf_refs.
+protobuf_refs. To prevent this condition, the protobuf_refs attribute
+and the first argument to protobuf_refs.set() must descend from the
+same containing object.
>>> c.guardians.add()
<keas.pbstate.testclasses_pb2.Ref object at ...>
- >>> c2.protobuf_refs[c.guardians[0]] = c
+ >>> c2.protobuf_refs.set(c.guardians[0], c)
>>> c.__getstate__()
Traceback (most recent call last):
...
KeyError: 'Object contains broken references: <Contact object at ...>'
- >>> del c2.protobuf_refs[c.guardians[0]]
>>> del c.guardians[0]
Don't omit the protobuf_type attribute.
Modified: keas.pbstate/trunk/src/keas/pbstate/meta.py
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/meta.py 2009-01-13 06:35:09 UTC (rev 94717)
+++ keas.pbstate/trunk/src/keas/pbstate/meta.py 2009-01-13 06:52:15 UTC (rev 94718)
@@ -109,7 +109,7 @@
class ProtobufReferences(object):
- """A mapping-like object that gets or sets the target of references.
+ """Gets or sets the target of references.
A reference is a protobuf message with a _p_refid field.
The target can be any kind of pickleable object, including derivatives
@@ -120,14 +120,14 @@
def __init__(self, targets):
self._targets = targets # {refid -> target}
- def __getitem__(self, message):
+ def get(self, ref_message, default=None):
"""Get a reference target"""
- refid = message._p_refid
+ refid = ref_message._p_refid
if not refid:
- raise KeyError("No reference set")
+ return default
return self._targets[refid]
- def __setitem__(self, message, target):
+ def set(self, ref_message, target):
"""Set the target of a reference message"""
targets = self._targets
refid = id(target) % 0xffffffff
@@ -135,14 +135,14 @@
while not refid or refid in targets:
refid = (refid + 1) % 0xffffffff
targets[refid] = target
- message._p_refid = refid
+ ref_message._p_refid = refid
- def __delitem__(self, message):
+ def delete(self, ref_message):
"""Unlink a target from a reference message"""
# We can't actually remove the reference from the reference mapping
# because something else might still have a reference. __getstate__
# will remove unused references.
- message._p_refid = 0
+ ref_message._p_refid = 0
def _get_targets(self, obj, used):
"""Clean out unused reference targets, then return the target dict.
More information about the Checkins
mailing list