[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