[Checkins] SVN: keas.pbstate/trunk/s Added tests (2 of which are failing at the moment)

Shane Hathaway shane at hathawaymix.org
Mon Jan 12 22:01:42 EST 2009


Log message for revision 94715:
  Added tests (2 of which are failing at the moment)
  

Changed:
  U   keas.pbstate/trunk/setup.py
  A   keas.pbstate/trunk/src/keas/pbstate/README.txt
  U   keas.pbstate/trunk/src/keas/pbstate/meta.py
  A   keas.pbstate/trunk/src/keas/pbstate/testclasses.proto
  A   keas.pbstate/trunk/src/keas/pbstate/testclasses_pb2.py
  A   keas.pbstate/trunk/src/keas/pbstate/tests.py

-=-
Modified: keas.pbstate/trunk/setup.py
===================================================================
--- keas.pbstate/trunk/setup.py	2009-01-13 02:37:21 UTC (rev 94714)
+++ keas.pbstate/trunk/setup.py	2009-01-13 03:01:41 UTC (rev 94715)
@@ -19,7 +19,7 @@
     version='0.1dev',
     author='Shane Hathaway and the Zope Community',
     author_email='zope-dev at zope.org',
-    description='Method of storing object state in a Google Protocol Buffer',
+    description='Object state storage in a Google Protocol Buffer',
     license='ZPL 2.1',
 
     package_dir={'': 'src'},

Added: keas.pbstate/trunk/src/keas/pbstate/README.txt
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/README.txt	                        (rev 0)
+++ keas.pbstate/trunk/src/keas/pbstate/README.txt	2009-01-13 03:01:41 UTC (rev 94715)
@@ -0,0 +1,178 @@
+
+=====
+Tests
+=====
+
+These are tests of keas.pbstate, a Python package that provides
+a method of storing object state in a Google Protocol Buffer.
+These tests also serve as basic documentation of this package.
+This package is designed to be compatible with ZODB, but ZODB is
+not required.
+
+These tests depend on the module named testclasses_pb2.py, which
+is generated from testclasses.proto using the following command:
+
+    protoc --python_out . *.proto
+
+Create a Contact class.
+
+    >>> import time
+    >>> from keas.pbstate.meta import ProtobufState
+    >>> from keas.pbstate.testclasses_pb2 import ContactPB
+    >>> class Contact(object):
+    ...     __metaclass__ = ProtobufState
+    ...     protobuf_type = ContactPB
+    ...     def __init__(self):
+    ...         self.create_time = int(time.time())
+    ...
+
+Create an instance of this class and verify the instance has the expected
+attributes.
+
+    >>> c = Contact()
+    >>> c.create_time > 0
+    True
+    >>> c.name
+    u''
+    >>> c.address.line1
+    u''
+    >>> c.address.country
+    u'United States'
+
+The instance also provides access to the protobuf message, its type (inherited
+from the class), and the references from the message.
+
+    >>> c.protobuf
+    <keas.pbstate.testclasses_pb2.ContactPB object at ...>
+    >>> c.protobuf_type
+    <class 'keas.pbstate.testclasses_pb2.ContactPB'>
+    >>> c.protobuf_refs
+    <keas.pbstate.meta.ProtobufReferences object at ...>
+
+Set and retrieve some of the attributes.
+
+    >>> c.name = u'John Doe'
+    >>> c.address.line1 = u'100 First Avenue'
+    >>> c.address.country = u'Canada'
+    >>> c.name
+    u'John Doe'
+    >>> c.address.country
+    u'Canada'
+
+Try to set one of the attributes to a value the protobuf message can't
+serialize.
+
+    >>> c.name = 100
+    Traceback (most recent call last):
+    ...
+    TypeError: 100 has type <type 'int'>, but expected one of: (<type 'str'>, <type 'unicode'>)
+    >>> c.name
+    u'John Doe'
+
+Try to set an attribute not declared in the .proto file.
+
+    >>> c.phone = u'555-1234'
+    Traceback (most recent call last):
+    ...
+    AttributeError: 'Contact' object has no attribute 'phone'
+
+Try to serialize the object without providing all of the required fields.
+
+    >>> c.__getstate__()
+    Traceback (most recent call last):
+    ...
+    EncodeError: Required field AddressPB.city is not set.
+
+Finish filling out the required fields, then serialize.
+
+    >>> c.address.city = u'Toronto'
+    >>> c.create_time = 1001
+    >>> c.__getstate__()
+    ('\x08\xe9\x07\x12\x08John Doe\x1a#\n\x10100 First Avenue\x1a\x07Toronto2\x06Canada', {})
+
+Create a contact and fill in its state from c.
+
+    >>> c_dup = Contact.__new__(Contact)
+    >>> c_dup.__setstate__(c.__getstate__())
+    >>> c_dup.name
+    u'John Doe'
+    >>> c_dup.address.country
+    u'Canada'
+
+Create another contact, but this time provide no address information.
+
+    >>> c2 = Contact()
+    >>> c2.create_time = 1002
+    >>> c2.name = u'Mary Anne'
+    >>> c2.__getstate__()
+    ('\x08\xea\x07\x12\tMary Anne', {})
+
+Add a guardian to c2, but don't say who the guardian is yet.
+
+    >>> guardian_ref = c2.guardians.add()
+
+Using the protobuf_refs attribute, assign c to be a guardian of c2.
+Note that the item interface of the protobuf_refs attribute is
+unusual.  Don't think of it like a mapping; just think of it as a way
+to refer to any object.  Under the covers, a reference
+ID will be generated, that ID will be assigned to guardian_ref._p_refid,
+and the refid and target object will be added to the internal
+state of the protobuf_refs object.  Any message with a _p_refid field
+is a reference.  Every _p_refid field should be of type uint32.
+
+    >>> c2.protobuf_refs[guardian_ref] = c
+
+Verify the reference is serialized correctly.
+
+    >>> data, targets = c2.__getstate__()
+    >>> targets[c2.guardians[0]._p_refid] is c
+    True
+
+
+Features Designed for ZODB
+--------------------------
+
+The _p_changed attribute, if it exists, is set to True whenever the protobuf
+changes.  Here is the PersistentContact class, which has a _p_changed
+attribute.
+
+    >>> class FakePersistent(object):
+    ...     __slots__ = ('_changed',)
+    ...     def _get_changed(self):
+    ...         return getattr(self, '_changed', False)
+    ...     def _set_changed(self, value):
+    ...         self._changed = value
+    ...     _p_changed = property(_get_changed, _set_changed)
+    ...
+    >>> class PersistentContact(FakePersistent):
+    ...     __metaclass__ = ProtobufState
+    ...     protobuf_type = ContactPB
+    ...
+
+    >>> c3 = PersistentContact()
+    >>> c3.create_time = 1003
+    >>> c3.name = u'Snoopy'
+    >>> c3._p_changed = False
+
+Reading an attribute does not set _p_changed.
+
+    >>> c3.name
+    u'Snoopy'
+    >>> c3._p_changed
+    False
+
+Writing an attribute sets _p_changed.
+
+    >>> c3.name = u'Woodstock'
+    >>> c3._p_changed
+    True
+
+Adding to a repeated element sets _p_changed.
+
+    >>> c3._p_changed = False
+    >>> c3._p_changed
+    False
+    >>> c3.guardians.add()
+    <keas.pbstate.testclasses_pb2.Ref object at ...>
+    >>> c3._p_changed
+    True

Modified: keas.pbstate/trunk/src/keas/pbstate/meta.py
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/meta.py	2009-01-13 02:37:21 UTC (rev 94714)
+++ keas.pbstate/trunk/src/keas/pbstate/meta.py	2009-01-13 03:01:41 UTC (rev 94715)
@@ -213,13 +213,10 @@
         # Arrange for class instances to always have the 'protobuf' and
         # 'protobuf_refs' instance attributes.  This is done by creating
         # or overriding the __new__() method of the new class.
-        parent__new__ = dct.get('__new__')
         def __new__(subclass, *args, **kw):
             # subclass is either created_class or a subclass of created_class.
-            create = parent__new__
-            if create is None:
-                create = super(created_class, subclass).__new__
-            instance = create(subclass, *args, **kw)
+            super_new = super(created_class, subclass).__new__
+            instance = super_new(subclass, *args, **kw)
             instance.protobuf_refs = ProtobufReferences({})
             instance.protobuf = subclass.protobuf_type()
             if hasattr(instance, '_p_changed'):

Added: keas.pbstate/trunk/src/keas/pbstate/testclasses.proto
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/testclasses.proto	                        (rev 0)
+++ keas.pbstate/trunk/src/keas/pbstate/testclasses.proto	2009-01-13 03:01:41 UTC (rev 94715)
@@ -0,0 +1,20 @@
+
+message Ref {
+    required uint32 _p_refid = 1;
+}
+
+message AddressPB {
+    required string line1 = 1;
+    optional string line2 = 2;
+    required string city = 3;
+    optional string state = 4;
+    optional string postal_code = 5;
+    required string country = 6 [default = 'United States'];
+}
+
+message ContactPB {
+    required uint64 create_time = 1;
+    required string name = 2;
+    optional AddressPB address = 3;
+    repeated Ref guardians = 4;
+}

Added: keas.pbstate/trunk/src/keas/pbstate/testclasses_pb2.py
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/testclasses_pb2.py	                        (rev 0)
+++ keas.pbstate/trunk/src/keas/pbstate/testclasses_pb2.py	2009-01-13 03:01:41 UTC (rev 94715)
@@ -0,0 +1,149 @@
+#!/usr/bin/python2.4
+# Generated by the protocol buffer compiler.  DO NOT EDIT!
+
+from google.protobuf import descriptor
+from google.protobuf import message
+from google.protobuf import reflection
+from google.protobuf import service
+from google.protobuf import service_reflection
+from google.protobuf import descriptor_pb2
+
+
+
+_REF = descriptor.Descriptor(
+  name='Ref',
+  full_name='Ref',
+  filename='src/keas/pbstate/testclasses.proto',
+  containing_type=None,
+  fields=[
+    descriptor.FieldDescriptor(
+      name='_p_refid', full_name='Ref._p_refid', index=0,
+      number=1, type=13, cpp_type=3, label=2,
+      default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],  # TODO(robinson): Implement.
+  enum_types=[
+  ],
+  options=None)
+
+
+_ADDRESSPB = descriptor.Descriptor(
+  name='AddressPB',
+  full_name='AddressPB',
+  filename='src/keas/pbstate/testclasses.proto',
+  containing_type=None,
+  fields=[
+    descriptor.FieldDescriptor(
+      name='line1', full_name='AddressPB.line1', index=0,
+      number=1, type=9, cpp_type=9, label=2,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='line2', full_name='AddressPB.line2', index=1,
+      number=2, type=9, cpp_type=9, label=1,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='city', full_name='AddressPB.city', index=2,
+      number=3, type=9, cpp_type=9, label=2,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='state', full_name='AddressPB.state', index=3,
+      number=4, type=9, cpp_type=9, label=1,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='postal_code', full_name='AddressPB.postal_code', index=4,
+      number=5, type=9, cpp_type=9, label=1,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='country', full_name='AddressPB.country', index=5,
+      number=6, type=9, cpp_type=9, label=2,
+      default_value=unicode("United States", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],  # TODO(robinson): Implement.
+  enum_types=[
+  ],
+  options=None)
+
+
+_CONTACTPB = descriptor.Descriptor(
+  name='ContactPB',
+  full_name='ContactPB',
+  filename='src/keas/pbstate/testclasses.proto',
+  containing_type=None,
+  fields=[
+    descriptor.FieldDescriptor(
+      name='create_time', full_name='ContactPB.create_time', index=0,
+      number=1, type=4, cpp_type=4, label=2,
+      default_value=0,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='name', full_name='ContactPB.name', index=1,
+      number=2, type=9, cpp_type=9, label=2,
+      default_value=unicode("", "utf-8"),
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='address', full_name='ContactPB.address', index=2,
+      number=3, type=11, cpp_type=10, label=1,
+      default_value=None,
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+    descriptor.FieldDescriptor(
+      name='guardians', full_name='ContactPB.guardians', index=3,
+      number=4, type=11, cpp_type=10, label=3,
+      default_value=[],
+      message_type=None, enum_type=None, containing_type=None,
+      is_extension=False, extension_scope=None,
+      options=None),
+  ],
+  extensions=[
+  ],
+  nested_types=[],  # TODO(robinson): Implement.
+  enum_types=[
+  ],
+  options=None)
+
+
+_CONTACTPB.fields_by_name['address'].message_type = _ADDRESSPB
+_CONTACTPB.fields_by_name['guardians'].message_type = _REF
+
+class Ref(message.Message):
+  __metaclass__ = reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _REF
+
+class AddressPB(message.Message):
+  __metaclass__ = reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _ADDRESSPB
+
+class ContactPB(message.Message):
+  __metaclass__ = reflection.GeneratedProtocolMessageType
+  DESCRIPTOR = _CONTACTPB
+

Added: keas.pbstate/trunk/src/keas/pbstate/tests.py
===================================================================
--- keas.pbstate/trunk/src/keas/pbstate/tests.py	                        (rev 0)
+++ keas.pbstate/trunk/src/keas/pbstate/tests.py	2009-01-13 03:01:41 UTC (rev 94715)
@@ -0,0 +1,27 @@
+##############################################################################
+#
+# Copyright (c) 2008 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 unittest
+
+from zope.testing import doctest
+
+def test_suite():
+    return unittest.TestSuite([
+        doctest.DocFileSuite(
+            'README.txt',
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
+    ])
+
+if __name__ == '__main__':
+    unittest.main()



More information about the Checkins mailing list