{ "info": { "author": "Shane Hathaway and the Zope Community", "author_email": "zope-dev@zope.org", "bugtrack_url": null, "classifiers": [], "description": "Overview\n========\n\nGoogle's Protocol Buffers project provides an interesting way to serialize\ndata. Protocol Buffer messages are efficient to produce and parse, flexible\nenough to weather schema changes, fairly expressive, and are usable in\nseveral programming languages.\n\nWhat if we combined those properties with an object database? Object\ndatabases often provide an excellent software foundation. Unfortunately,\nobject databases are generally bound to a single programming language.\nThis package provides object serialization using Protocol Buffers,\nconceivably making it possible to build an object database that\nmultiple programming languages can access.\n\nUsing this package also provides schema documentation. The Protocol Buffers\npackage requires programmers to write the schema of their data in a\nconcise form that also serves as documentation of the schema. While it's\nusually possible to guess at the schema by looking at application\ncode, having it written out in Protocol Buffer format is much more\ndirect and informative.\n\nThis package is designed to be combined with an object database such as\nZODB, but this package does not require ZODB.\n\n\nTests\n=====\n\nThe tests below describe how to use this package.\nThese tests depend on the module named testclasses_pb2.py, which\nis generated from testclasses.proto using the following command,\navailable once the Google Protocol Buffers package is installed::\n\n protoc --python_out . *.proto\n\nCreate a Contact class. Notice its metaclass. The metaclass adds\nproperties to the class so that you can read and write protocol\nbuffer message fields using simple attribute access. The\n'create_time' attribute is one such field.\n\n >>> import time\n >>> from keas.pbstate.meta import ProtobufState\n >>> from keas.pbstate.testclasses_pb2 import ContactPB\n >>> class Contact(object):\n ... __metaclass__ = ProtobufState\n ... protobuf_type = ContactPB\n ... def __init__(self):\n ... self.create_time = int(time.time())\n ...\n\nCreate an instance of this class and verify the instance has the expected\nattributes. These attributes are all described in the .proto file.\n\n >>> c = Contact()\n >>> c.create_time > 0\n True\n >>> c.name\n u''\n >>> c.address.line1\n u''\n >>> c.address.country\n u'United States'\n\nThe instance also provides access to the protobuf message, its type (inherited\nfrom the class), and the references from the message. References will be\ndiscussed later.\n\n >>> c.protobuf\n \n >>> c.protobuf_type\n \n >>> c.protobuf_refs\n \n\nSet and retrieve some of the attributes.\n\n >>> c.name = u'John Doe'\n >>> c.address.line1 = u'100 First Avenue'\n >>> c.address.country = u'Canada'\n >>> c.name\n u'John Doe'\n >>> c.address.country\n u'Canada'\n\nTry to set one of the attributes to a value the protobuf message can't\nserialize.\n\n >>> c.name = 100\n Traceback (most recent call last):\n ...\n TypeError: 100 has type , but expected one of: (, )\n >>> c.name\n u'John Doe'\n\nTry to set an attribute not declared in the .proto file.\n\n >>> c.phone = u'555-1234'\n Traceback (most recent call last):\n ...\n AttributeError: 'Contact' object has no attribute 'phone'\n\n\nMixins\n------\n\nA class can mix in properties that access sub-messages. This is\nuseful when subclassing (although subclassing should be avoided in general).\n\nHere is a class that mixes the ContactPB properties and the AddressPB\nproperties in a single class.\n\n >>> class MixedContact(object):\n ... __metaclass__ = ProtobufState\n ... protobuf_type = ContactPB\n ... protobuf_mixins = ('address',)\n\n >>> mc = MixedContact()\n >>> mc.line1 = u'180 Market St.'\n >>> mc.line1\n u'180 Market St.'\n >>> mc.address.line1\n u'180 Market St.'\n\n\nSerialization\n-------------\n\nThe ProtobufState also provides __getstate__ and __setstate__ methods,\nwhich Python uses for serialization purposes.\n\nTry to serialize the object without providing all of the required fields.\n\n >>> c.__getstate__()\n Traceback (most recent call last):\n ...\n EncodeError: Required field AddressPB.city is not set.\n\nFinish filling out the required fields, then serialize.\n\n >>> c.address.city = u'Toronto'\n >>> c.create_time = 1001\n >>> c.__getstate__()\n ('\\x08\\xe9\\x07\\x12\\x08John Doe\\x1a#\\n\\x10100 First Avenue\\x1a\\x07Toronto2\\x06Canada', {})\n\nCreate a contact and copy its state from c.\n\n >>> c_dup = Contact.__new__(Contact)\n >>> c_dup.__setstate__(c.__getstate__())\n >>> c_dup.name\n u'John Doe'\n >>> c_dup.address.country\n u'Canada'\n\nCreate another contact, but this time provide no address information.\n\n >>> c2 = Contact()\n >>> c2.create_time = 1002\n >>> c2.name = u'Mary Anne'\n >>> c2.__getstate__()\n ('\\x08\\xea\\x07\\x12\\tMary Anne', {})\n\n\nObject References\n-----------------\n\nClasses using the ProtobufState metaclass support references to arbitrary\nobjects through the use of the 'protobuf_refs' attribute.\n\nOur Contact class has a 'guardians' attribute that contains a list of\nreferences. The ProtobufState metaclass treats any message or sub-message\nwith a _p_refid field as a reference.\n\nAdd a guardian to c2, but don't say who the guardian is yet.\n\n >>> guardian_ref = c2.guardians.add()\n\nCall protobuf_refs.set() to make guardian_ref refer to c.\n\n >>> c2.protobuf_refs.set(guardian_ref, c)\n\nLet's go over what happened. The set method generated a reference ID, then\nthat ID was assigned to guardian_ref._p_refid, and the refid and target object\nwere added to the internal state of the protobuf_refs instance. Any message\nwith a _p_refid field is a reference. Every _p_refid field should be\nof type uint32.\n\nRead the reference.\n\n >>> c2.protobuf_refs.get(guardian_ref) is c\n True\n\nVerify the reference gets serialized correctly.\n\n >>> data, targets = c2.__getstate__()\n >>> targets[c2.guardians[0]._p_refid] is c\n True\n\nDelete the reference.\n\n >>> c2.protobuf_refs.delete(guardian_ref)\n >>> c2.protobuf_refs.get(guardian_ref, 'gone')\n 'gone'\n\nVerify the reference is no longer contained in the serialized state.\n\n >>> data, targets = c2.__getstate__()\n >>> len(targets)\n 0\n\n\nFeatures Designed for ZODB\n--------------------------\n\nThis package provides enough features for storing ProtobufState objects\nin ZODB, although without the keas.pbpersist package, the stored objects\nwill still be wrapped inside a Python pickle, making them hard for\nlanguages other than Python to access. See the keas.pbpersist package\nfor a straightforward method of storing ProtobufState objects in ZODB\nwithout using Python pickles.\n\nIn ZODB, objects have a _p_changed attribute to indicate when they\nare dirty. The ProtobufState metaclass causes instances to modify\nthe _p_changed attribute if it exists; it is set to True whenever the\nmessage changes.\n\nHere is a PersistentContact class, which has a _p_changed attribute.\n(We also define a FakePersistent base class in order to avoid\ndepending on ZODB.)\n\n >>> class FakePersistent(object):\n ... __slots__ = ('_changed',)\n ... def _get_changed(self):\n ... return getattr(self, '_changed', False)\n ... def _set_changed(self, value):\n ... self._changed = value\n ... if not value:\n ... # reset the _cache_byte_size_dirty flags\n ... self.protobuf.ByteSize()\n ... _p_changed = property(_get_changed, _set_changed)\n ...\n >>> class PersistentContact(FakePersistent):\n ... __metaclass__ = ProtobufState\n ... protobuf_type = ContactPB\n ...\n\n >>> c3 = PersistentContact()\n >>> c3._p_changed\n False\n >>> c3.create_time = 1003\n >>> c3.name = u'Snoopy'\n >>> c3._p_changed = False\n\nReading an attribute does not set _p_changed.\n\n >>> c3.name\n u'Snoopy'\n >>> c3._p_changed\n False\n\nWriting an attribute sets _p_changed.\n\n >>> c3.name = u'Woodstock'\n >>> c3._p_changed\n True\n\nAdding to a repeated element sets _p_changed.\n\n >>> c3._p_changed = False\n >>> c3._p_changed\n False\n >>> c3.guardians.add()\n \n >>> c3._p_changed\n True\n >>> del c3.guardians[0]\n\nA copy of c3 should initially have _p_changed = False; setting an attribute\nshould set _p_changed to true.\n\n >>> c4 = PersistentContact.__new__(PersistentContact)\n >>> c4.__setstate__(c3.__getstate__())\n >>> c4._p_changed\n False\n >>> c4.name = u'Linus'\n >>> c4._p_changed\n True\n\nThe tuple returned by __getstate__ is actually a subclass of tuple. The\nStateTuple suggests to the ZODB serializer that it can save the state\nin a different format than the default pickle format.\n\n >>> type(c.__getstate__())\n \n >>> c.__getstate__().serial_format\n 'protobuf'\n\n\nEdge Cases\n----------\n\nSynthesize a refid hash collision. This is a rare occurrence, but\nthis package should handle it transparently as long as no single object\nholds more than about one billion (2**30) references to other objects.\n\nFirst make a reference:\n\n >>> guardian_ref = c2.guardians.add()\n >>> c2.protobuf_refs.set(guardian_ref, c)\n\nCovertly change the target of that reference:\n\n >>> c2.protobuf_refs._targets[guardian_ref._p_refid] = mc\n\nAdd a new reference to the original target. The first generated refid\nwill collide, but he protobuf_refs should should choose a different\nrefid automatically.\n\n >>> guardian2_ref = c2.guardians.add()\n >>> c2.protobuf_refs.set(guardian2_ref, c)\n >>> guardian_ref._p_refid == guardian2_ref._p_refid\n False\n\n\nException Conditions\n--------------------\n\nDeleting message attributes is not allowed.\n\n >>> del c.name\n Traceback (most recent call last):\n ...\n AttributeError: can't delete attribute\n >>> del mc.line1\n Traceback (most recent call last):\n ...\n AttributeError: can't delete attribute\n\nMixin names are checked.\n\n >>> class MixedUpContact(object):\n ... __metaclass__ = ProtobufState\n ... protobuf_type = ContactPB\n ... protobuf_mixins = ('bogus',)\n Traceback (most recent call last):\n ...\n AttributeError: Field 'bogus' not defined for protobuf type <...>\n\nCreate a broken reference by setting a reference using the wrong\nprotobuf_refs. To prevent this condition, the protobuf_refs attribute\nand the first argument to protobuf_refs.set() must descend from the\nsame containing object.\n\n >>> c.guardians.add()\n \n >>> c2.protobuf_refs.set(c.guardians[0], c)\n >>> c.__getstate__()\n Traceback (most recent call last):\n ...\n KeyError: 'Object contains broken references: '\n >>> del c.guardians[0]\n\nDon't omit the protobuf_type attribute.\n\n >>> class FailedContact(object):\n ... __metaclass__ = ProtobufState\n Traceback (most recent call last):\n ...\n TypeError: Class ...FailedContact needs a protobuf_type attribute", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "UNKNOWN", "keywords": null, "license": "ZPL 2.1", "maintainer": null, "maintainer_email": null, "name": "keas.pbstate", "package_url": "https://pypi.org/project/keas.pbstate/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/keas.pbstate/", "project_urls": { "Download": "UNKNOWN", "Homepage": "UNKNOWN" }, "release_url": "https://pypi.org/project/keas.pbstate/0.1.1/", "requires_dist": null, "requires_python": null, "summary": "An object database foundation based on Google's Protocol Buffers", "version": "0.1.1" }, "last_serial": 683103, "releases": { "0.1": [ { "comment_text": "", "digests": { "md5": "de84776e0c53f8cc69ed8e85d0f51755", "sha256": "276881b0acddf9c5c29108d7d347162c7d1cea53228e0f1ccfbdaec3dd24c4dd" }, "downloads": -1, "filename": "keas.pbstate-0.1.tar.gz", "has_sig": false, "md5_digest": "de84776e0c53f8cc69ed8e85d0f51755", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11033, "upload_time": "2009-01-27T23:54:53", "url": "https://files.pythonhosted.org/packages/f1/13/41329d41ff3ca38fc548b0a698c618f6faaca4bf174b05153f3d6e8ee814/keas.pbstate-0.1.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "a354b21cd1f51bab6f3ac73dc40d8b94", "sha256": "f25d48da36adcf88fc523de7af2e6e1c7acc41150b01fc4e80f61cc8a473e79f" }, "downloads": -1, "filename": "keas.pbstate-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a354b21cd1f51bab6f3ac73dc40d8b94", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11030, "upload_time": "2009-01-28T01:51:14", "url": "https://files.pythonhosted.org/packages/c8/58/78f314b4ca8e5ea906f976fcea039dec159b2b8e3823b4619eca87c2a853/keas.pbstate-0.1.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "a354b21cd1f51bab6f3ac73dc40d8b94", "sha256": "f25d48da36adcf88fc523de7af2e6e1c7acc41150b01fc4e80f61cc8a473e79f" }, "downloads": -1, "filename": "keas.pbstate-0.1.1.tar.gz", "has_sig": false, "md5_digest": "a354b21cd1f51bab6f3ac73dc40d8b94", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11030, "upload_time": "2009-01-28T01:51:14", "url": "https://files.pythonhosted.org/packages/c8/58/78f314b4ca8e5ea906f976fcea039dec159b2b8e3823b4619eca87c2a853/keas.pbstate-0.1.1.tar.gz" } ] }