[Checkins] SVN: Sandbox/paulwilson/z3c.schema2json/ Initial import of package.

Paul Wilson paulalexwilson at gmail.com
Sun Jun 28 19:09:57 EDT 2009


Log message for revision 101308:
  Initial import of package.
  

Changed:
  A   Sandbox/paulwilson/z3c.schema2json/
  A   Sandbox/paulwilson/z3c.schema2json/CHANGES.txt
  A   Sandbox/paulwilson/z3c.schema2json/COPYRIGHT.txt
  A   Sandbox/paulwilson/z3c.schema2json/CREDITS.txt
  A   Sandbox/paulwilson/z3c.schema2json/LICENSE.txt
  A   Sandbox/paulwilson/z3c.schema2json/TODO.txt
  A   Sandbox/paulwilson/z3c.schema2json/bootstrap.py
  A   Sandbox/paulwilson/z3c.schema2json/buildout.cfg
  A   Sandbox/paulwilson/z3c.schema2json/setup.py
  A   Sandbox/paulwilson/z3c.schema2json/src/
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/__init__.py
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/README.txt
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/__init__.py
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/_schema2json.py
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/configure.zcml
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/ftesting.zcml
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/testing.py
  A   Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/tests.py

-=-
Added: Sandbox/paulwilson/z3c.schema2json/CHANGES.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/CHANGES.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/CHANGES.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,7 @@
+CHANGES
+*******
+
+0.10 (2009-XXX)
+=================
+
+* First checkin in svn.zope.org.


Property changes on: Sandbox/paulwilson/z3c.schema2json/CHANGES.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/COPYRIGHT.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/COPYRIGHT.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/COPYRIGHT.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,9 @@
+Copyright (c) 2007-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. 


Property changes on: Sandbox/paulwilson/z3c.schema2json/COPYRIGHT.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/CREDITS.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/CREDITS.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/CREDITS.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,17 @@
+=======================
+z3c.schema2json credits
+=======================
+
+Developers
+----------
+
+* Paul A. Wilson
+
+Thank You
+----------
+
+The developers of z3c.schema2json for inspiration:
+
+* Jan-Wijbrand Kolman
+
+* Martijn Faassen 


Property changes on: Sandbox/paulwilson/z3c.schema2json/CREDITS.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/LICENSE.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/LICENSE.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/LICENSE.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,54 @@
+Zope Public License (ZPL) Version 2.1
+-------------------------------------
+
+A copyright notice accompanies this license document that
+identifies the copyright holders.
+
+This license has been certified as open source. It has also
+been designated as GPL compatible by the Free Software
+Foundation (FSF).
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+1. Redistributions in source code must retain the
+   accompanying copyright notice, this list of conditions,
+   and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the accompanying
+   copyright notice, this list of conditions, and the
+   following disclaimer in the documentation and/or other
+   materials provided with the distribution.
+
+3. Names of the copyright holders must not be used to
+   endorse or promote products derived from this software
+   without prior written permission from the copyright
+   holders.
+
+4. The right to distribute this software or to use it for
+   any purpose does not give you the right to use
+   Servicemarks (sm) or Trademarks (tm) of the copyright
+   holders. Use of them is covered by separate agreement
+   with the copyright holders.
+
+5. If any files are modified, you must cause the modified
+   files to carry prominent notices stating that you changed
+   the files and the date of any change.
+
+Disclaimer
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS''
+  AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
+  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+  NO EVENT SHALL THE COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+  DAMAGE.


Property changes on: Sandbox/paulwilson/z3c.schema2json/LICENSE.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/TODO.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/TODO.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/TODO.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,4 @@
+Todo
+====
+
+ * Update the changes page to reflect relevent stuff


Property changes on: Sandbox/paulwilson/z3c.schema2json/TODO.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/bootstrap.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/bootstrap.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/bootstrap.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,52 @@
+##############################################################################
+#
+# Copyright (c) 2006 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.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 73916 2007-03-29 15:28:25Z dobe $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+assert os.spawnle(
+    os.P_WAIT, sys.executable, sys.executable,
+    '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+    dict(os.environ,
+         PYTHONPATH=
+         ws.find(pkg_resources.Requirement.parse('setuptools')).location
+         ),
+    ) == 0
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)


Property changes on: Sandbox/paulwilson/z3c.schema2json/bootstrap.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/buildout.cfg
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/buildout.cfg	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/buildout.cfg	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,18 @@
+[buildout]
+develop = .
+parts = test devpython
+extends = http://grok.zope.org/releaseinfo/grok-0.14.cfg
+versions = versions
+
+[versions]
+zope.testing >= 3.6.0
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.schema2json
+
+# installs bin/devpython to do simple interpreter tests
+[devpython]
+recipe = zc.recipe.egg
+interpreter = devpython
+eggs = z3c.schema2json


Property changes on: Sandbox/paulwilson/z3c.schema2json/buildout.cfg
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/setup.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/setup.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/setup.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,38 @@
+from setuptools import setup, find_packages
+import sys, os
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+long_description = (
+    read('src', 'z3c', 'schema2json', 'README.txt')
+    + '\n' +
+    read('CHANGES.txt')
+    + '\n' +
+    'Download\n'
+    '********\n'
+    )
+
+setup(name='z3c.schema2json',
+      version='1.1dev',
+      description="Convert schema-described Zope 3 objects to JSON and back",
+      long_description=long_description,
+      classifiers=[],
+      keywords="",
+      author="Paul A Wilson",
+      author_email="paulalexwilson at gmail.com",
+      url="",
+      license="ZPL",
+      package_dir={'': 'src'},
+      packages=find_packages('src'),
+      namespace_packages=['z3c'],
+      include_package_data=True,
+      zip_safe=False,
+      install_requires=[
+        'setuptools',
+        'grokcore.component',
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )


Property changes on: Sandbox/paulwilson/z3c.schema2json/setup.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/__init__.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/__init__.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/__init__.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,8 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)
+


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/__init__.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/README.txt
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/README.txt	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/README.txt	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,556 @@
+.. -*- coding: utf-8 -*-
+Schema To JSON
+**************
+
+Introduction
+============
+
+``z3c.schema2json`` can take objects enriched with schema definitions
+into the popular JSON serialisation format. It is also capable of 
+converting this JSON back into objects. 
+
+This package requires ``simplejson`` or Python version 2.6 (which has
+simplejson as part of the standard library). 
+
+Only object attributes described by zope schema are recognised by 
+this package. Any attributes that do no have corresponding schema 
+descriptions will be lost in the serialization/deserialization process.
+
+Serialization
+=============
+
+Let's first define a simple Zope 3 schema::
+
+    >>> from zope import interface, schema
+    >>> class IName(interface.Interface):
+    ...     first_name = schema.TextLine(title=u'First name')
+    ...     last_name = schema.TextLine(title=u'Last name')
+
+Let's now create a class that implements this schema::
+
+    >>> from zope.interface import implements
+    >>> class Name(object):
+    ...     implements(IName)
+    ...     def __init__(self, first_name, last_name):
+    ...         self.first_name = first_name
+    ...         self.last_name = last_name
+
+Now we make an instance of the class::
+
+    >>> name = Name('Paul', 'Tom')
+
+Now let's serialize it to JSON::
+    
+    >>> from z3c.schema2json import serialize
+    >>> print serialize(IName, name)
+    {
+      "first_name": "Paul",
+      "last_name": "Tom"
+    }
+
+Since the class is part of a doctest, it's module becomes ``__builtin__``.
+
+We can also serialise other fields too::
+
+    >>> from zope import interface, schema
+    >>> class IAddress(interface.Interface):
+    ...     street_name = schema.TextLine(title=u'Street name')
+    ...     number = schema.Int(title=u'House Number')
+    >>> class Address(object):
+    ...     implements(IAddress)
+    ...     def __init__(self, street_name, number):
+    ...         self.street_name = street_name
+    ...         self.number = number
+    >>> address = Address('Pendle Road', 15)
+    >>> print serialize(IAddress, address)
+    {
+      "number": 15,
+      "street_name": "Pendle Road"
+    }
+
+A schema can define an ``Object`` field with its own schema, which the
+serialisation process can handle::
+
+    >>> class IPerson(interface.Interface):
+    ...     name = schema.Object(title=u"Name", schema=IName)
+    ...     address =schema.Object(title=u"Address", schema=IAddress)
+
+    >>> class Person(object):
+    ...     implements(IPerson)
+    ...     def __init__(self, name, address):
+    ...         self.name = name
+    ...         self.address = address
+
+    >>> person = Person(name, address)
+    >>> print serialize(IPerson, person)
+    {
+      "address": {
+        "number": 15,
+        "street_name": "Pendle Road"
+      },
+      "name": {
+        "first_name": "Paul",
+        "last_name": "Tom"
+      }
+    }
+
+The serialisation process also works for the List schema type containing
+elements with their own schema::
+
+    >>> class ICommission(interface.Interface):
+    ...     members = schema.List(
+    ...         title = u"Commission",
+    ...         value_type=schema.Object(__name__='person',
+    ...         schema=IPerson))
+
+Note that we have to explicitly specify __name__ for the field that's
+used for value_type here, otherwise we have no name to serialize to
+JSON with::
+
+    >>> class Commission(object):
+    ...     implements(ICommission)
+    ...     def __init__(self, members):
+    ...         self.members = members
+
+    >>> commission = Commission(
+    ...     [person, Person(Name('Jim', 'Bo'), Address('Sci Road', 3))])
+    >>> print serialize(ICommission, commission)
+    {
+      "members": [
+        {
+          "address": {
+            "number": 15,
+            "street_name": "Pendle Road"
+          },
+          "name": {
+            "first_name": "Paul",
+            "last_name": "Tom"
+          }
+        },
+        {
+          "address": {
+            "number": 3,
+            "street_name": "Sci Road"
+          },
+          "name": {
+            "first_name": "Jim",
+            "last_name": "Bo"
+          }
+        }
+      ]
+    }
+
+We get an adapter lookup failure whenever we attempt to serialize a field
+type which there's no serializer::
+
+    >>> class IWithNonSerializableField(interface.Interface):
+    ...    field = schema.Field(title=u"Commission")
+    >>> class NotSerializable(object):
+    ...     implements(IWithNonSerializableField)
+    ...     def __init__(self, value):  
+    ...         self.field = value
+    >>> not_serializable = NotSerializable(None)
+    >>> serialize(IWithNonSerializableField, not_serializable)
+    Traceback (most recent call last):
+     ...
+    TypeError: ('Could not adapt', <zope.schema._bootstrapfields.Field object at ...>, <InterfaceClass z3c.schema2json._schema2json.IJSONGenerator>)
+
+List fields an also contain more primitive values (rather than Objects) such as Ints::
+
+    >>> class ILottery(interface.Interface):
+    ...     numbers = schema.List(
+    ...         title = u"Lottery Numbers",
+    ...         value_type = schema.Int(title=u"A Lottery Number",
+    ...                                 min=0, max=49))
+    >>> class Lottery(object):
+    ...     implements(ILottery)
+    ...     def __init__(self, numbers):
+    ...         self.numbers = numbers
+    ...
+    >>> lotto = Lottery([10, 17, 20, 21, 23, 31, 32])
+    >>> print serialize(ILottery, lotto)
+    {
+       "numbers": [
+        10,
+        17,
+        20,
+        21,
+        23,
+        31,
+        32
+      ]
+    }
+
+
+Deserialization
+===============
+
+Now we would like to take some objects represented as JSON strings and 
+deserialize them::
+
+    >>> from z3c.schema2json import deserialize
+    >>> json = '''
+    ... {
+    ...   "first_name": "Guido",
+    ...   "last_name": "Van Rossum"
+    ... }
+    ... '''
+    ... name = Name('', '')
+    >>> deserialize(json, IName, name)
+    >>> name.first_name
+    u'Guido'
+    >>> name.last_name
+    u'Van Rossum'
+
+The order of the fields in the JSON string is irrelevant::
+
+    >>> json = '''
+    ... {
+    ...   "last_name": "Van Rossum",
+    ...   "first_name": "Guido"
+    ... }
+    ... '''
+    ... name = Name('', '')
+    >>> deserialize(json, IName, name)
+    >>> name.first_name
+    u'Guido'
+    >>> name.last_name
+    u'Van Rossum'
+
+After deserialization, the object ``alsoProvides`` the schema interface::
+
+    >>> IName.providedBy(name)
+    True
+
+This also works for other kinds of fields::
+
+    >>> json = '''
+    ... {
+    ...   "street_name": "Baker Street",
+    ...   "number": 221
+    ... }
+    ... '''
+    >>> address = Address('',0)
+    >>> deserialize(json, IAddress, address)
+    >>> address.street_name
+    u'Baker Street'
+    >>> address.number
+    221
+
+If a schema defines an Object field with its own schema, the serialization
+can also handle this::
+
+    >>> json = '''
+    ... {
+    ...   "name": {
+    ...      "first_name": "Sherlock",
+    ...      "last_name": "Holmes"
+    ...    },
+    ...   "address": {
+    ...      "street_name": "Baker Street",
+    ...      "number": 221
+    ...    }
+    ... }
+    ... '''
+    >>> person = Person(Name('', ''), Address('', 0))
+    >>> deserialize(json, IPerson, person)
+    >>> person.name.first_name
+    u'Sherlock'
+    >>> person.name.last_name
+    u'Holmes'
+    >>> person.address.street_name
+    u'Baker Street'
+    >>> person.address.number
+    221
+    >>> IPerson.providedBy(person)
+    True
+    >>> IName.providedBy(person.name)
+    True
+    >>> IAddress.providedBy(person.address)
+    True
+
+Again the order in which the fields come in JSON shouldn't matter::
+
+    >>> json = '''
+    ... {
+    ...   "address": {
+    ...     "number": 221,
+    ...     "street_name": "Baker Street"
+    ...   },
+    ...   "name": {
+    ...     "last_name": "Holmes",
+    ...     "first_name": "Sherlock"
+    ...    }
+    ... }
+    ... '''   
+    >>> person = Person(Name('', ''), Address('', 0))
+    >>> deserialize(json, IPerson, person)
+    >>> person.name.first_name
+    u'Sherlock'
+    >>> person.name.last_name
+    u'Holmes'
+    >>> person.address.street_name
+    u'Baker Street'
+    >>> person.address.number
+    221
+    >>> IPerson.providedBy(person)
+    True
+    >>> IName.providedBy(person.name)
+    True
+    >>> IAddress.providedBy(person.address)
+    True
+
+We can deserialise List types also::
+
+    >>> json = '''
+    ... {
+    ...   "members": [
+    ...    {
+    ...       "name": {
+    ...         "first_name": "Melanie",
+    ...         "last_name": "Parker"
+    ...       },
+    ...       "address": {
+    ...         "street_name": "Chaigley Court",
+    ...         "number": 23
+    ...      }
+    ...     },
+    ...     {
+    ...       "name": {
+    ...         "first_name": "Rob",
+    ...         "last_name": "Hall"
+    ...       },
+    ...       "address": {
+    ...         "street_name": "Queenswood Mount",
+    ...         "number": 2
+    ...       }
+    ...     }
+    ...   ]
+    ... }
+    ... '''
+
+    >>> commission = Commission([])
+    >>> deserialize(json, ICommission, commission)
+    >>> len(commission.members)
+    2
+    >>> member = commission.members[0]
+    >>> member.name.first_name
+    u'Melanie'
+    >>> member.address.street_name
+    u'Chaigley Court'
+    >>> member = commission.members[1]
+    >>> member.name.first_name
+    u'Rob'
+    >>> member.address.street_name
+    u'Queenswood Mount'
+
+Whenever an item is null, the resulting value should be None::
+
+    >>> json = '''
+    ... {
+    ...   "first_name": "",
+    ...   "last_name": null
+    ... }
+    ... '''
+    >>> name = Name('', '')
+    >>> deserialize(json, IName, name)
+    >>> name.first_name == ''
+    True
+    >>> name.last_name is None
+    True
+
+For all kinds of fields, like strings and ints...::
+
+    >>> json = '''
+    ... {
+    ...    "street_name": null,
+    ...    "number": null
+    ... }
+    ... '''
+    >>> address = Address('', 0)
+    >>> deserialize(json, IAddress, address)
+    >>> address.street_name is None
+    True
+    >>> address.number is None
+    True
+
+...and the fields of subobjects (but not the subobject themselves!)::
+
+    >>> json = '''
+    ... {
+    ...      "name": {
+    ...       "first_name": null,
+    ...       "last_name": null
+    ...      },
+    ...      "address": {
+    ...       "street_name": null,
+    ...       "number": null
+    ...     }
+    ... }
+    ... '''
+    >>> person = Person(Name('', ''), Address('', 0))
+    >>> deserialize(json, IPerson, person)
+    >>> person.name.first_name is None
+    True
+    >>> person.name.last_name is None
+    True
+    >>> IPerson.providedBy(person)
+    True
+    >>> IName.providedBy(person.name)
+    True
+    >>> person.address is None
+    False
+    >>> person.address.street_name is None
+    True
+    >>> person.address.number is None
+    True
+    >>> IAddress.providedBy(person.address)
+    True
+
+Similarly, empty sequencies result in an empty list::
+
+    >>> json = '''
+    ... {
+    ...   "members" : null
+    ... }
+    ... '''
+    >>> commission = Commission([])
+    >>> deserialize(json, ICommission, commission)
+    >>> len(commission.members)
+    0
+
+Thus concludes the testing for TextLine, Int Object and List. We will now test other supported field types.
+
+Datetime
+========
+
+Datetime objects::
+
+    >>> from datetime import datetime
+    >>> class IWithDatetime(interface.Interface):
+    ...     datetime = schema.Datetime(title=u'Date and Time')
+    >>> class WithDatetime(object):
+    ...     implements(IWithDatetime)
+    ...     def __init__(self, datetime):
+    ...         self.datetime = datetime
+    >>> with_datetime = WithDatetime(datetime(2008, 12, 31))
+    >>> json = serialize(IWithDatetime, with_datetime)
+    >>> print json
+    {
+       "datetime": "2008-12-31T00:00:00"
+    }
+    >>> new_datetime = WithDatetime(None)
+    >>> deserialize(json, IWithDatetime, new_datetime)
+    >>> new_datetime.datetime.year
+    2008
+    >>> new_datetime.datetime.month
+    12
+    >>> new_datetime.datetime.day
+    31
+
+Let's try it with the field not filled in::
+
+    >>> with_datetime = WithDatetime(None)
+    >>> json = serialize(IWithDatetime, with_datetime)
+    >>> print json
+    {
+      "datetime": null
+    }
+    >>> new_datetime = WithDatetime(None)
+    >>> deserialize(json, IWithDatetime, new_datetime)
+    >>> new_datetime.datetime is None
+    True
+
+Choice
+======
+
+Choice fields. Currently, only Choice fields with text values are supported::
+
+    >>> from zc.sourcefactory.basic import BasicSourceFactory
+    >>> class ChoiceSource(BasicSourceFactory):
+    ...     def getValues(self):
+    ...         return [u'alpha', u'beta']
+    >>> class IWithChoice(interface.Interface):
+    ...     choice = schema.Choice(title=u'Choice', required=False,
+    ...                           source=ChoiceSource())
+    >>> class WithChoice(object):
+    ...     implements(IWithChoice)
+    ...     def __init__(self, choice):
+    ...         self.choice = choice
+
+Let's serialize a choice::
+
+    >>> with_choice = WithChoice('alpha')
+    >>> json = serialize(IWithChoice, with_choice)
+    >>> print json
+    {
+      "choice": "alpha"
+    }
+
+And then deserialize it::
+
+    >>> new_choice = WithChoice(None)
+    >>> deserialize(json, IWithChoice, new_choice)
+    >>> new_choice.choice
+    'alpha'
+
+Serializing empty choices::
+
+    >>> with_choice = WithChoice(None)
+    >>> json = serialize(IWithChoice, with_choice)
+    >>> print json
+    {
+       "choice": null
+    }
+
+And then deserializing them::
+
+    >>> deserialize(json, IWithChoice, new_choice)
+    >>> new_choice.choice is None
+    True
+
+Set
+===
+
+Set fields are very similar to List fields::
+
+    >>> class IWithSet(interface.Interface):
+    ...     set = schema.Set(title=u'Set', required=False,
+    ...                      value_type=schema.Choice(__name__='choice',
+    ...                                               source=ChoiceSource()))
+    >>> class WithSet(object):
+    ...     implements(IWithSet)
+    ...     def __init__(self, set):
+    ...         self.set = set
+    >>> with_set = WithSet(set(['alpha']))
+    >>> json = serialize(IWithSet, with_set)
+    >>> print json
+    {
+      "set": [
+          "alpha"
+      ]
+    }
+    >>> with_set = WithSet(set(['alpha', 'beta']))
+    >>> json = serialize(IWithSet, with_set)
+    >>> print json
+    {
+      "set": [
+          "alpha",
+          "beta"
+      ]
+    }
+    >>> new_set = WithSet(None)
+    >>> deserialize(json, IWithSet, new_set)
+    >>> new_set.set
+    set(['alpha', 'beta'])
+
+Formatting
+==========
+
+The serializer allows both a human readible format and a compact
+JSON representation to be produced. By default, the human readible
+option is selected, but this may be overridden::
+
+    >>> name = Name('Paul', 'Tom') 
+    >>> print serialize(IName, name, pretty_print=False)
+    {"first_name": "Paul", "last_name": "Tom"}


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/README.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/__init__.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/__init__.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/__init__.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,2 @@
+from _schema2json import serialize
+from _schema2json import deserialize


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/__init__.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/_schema2json.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/_schema2json.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/_schema2json.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,157 @@
+try:
+    import json # Python v2.6
+except ImportError:
+    import simplejson as json
+
+import grokcore.component as grok
+import zope.datetime
+from persistent import Persistent
+from zope.interface import Interface, alsoProvides
+from zope.location import Location
+from zope.schema import getFieldsInOrder
+from zope.schema.interfaces import IText, IInt, IObject, IList, IChoice, ISet
+from zope.schema.interfaces import IDatetime
+
+def serialize_to_tree(container, schema, instance):
+    for name, field in getFieldsInOrder(schema):
+        value = field.get(instance)
+        container[name] = IJSONGenerator(field).output(value)
+
+def serialize(schema, instance, encoding='UTF-8',
+              pretty_print=True):
+    json_dict = {}
+    serialize_to_tree(json_dict, schema, instance)
+    if pretty_print:
+        indent = 2
+    else:
+        indent = None
+    return json.dumps(json_dict, sort_keys=True, indent=indent)
+
+def deserialize_from_dict(container, schema, instance):
+    for key, value in container.iteritems():
+        field = schema[key]
+        value = IJSONGenerator(field).input(value)
+        field.set(instance, value)
+    
+    alsoProvides(instance, schema)
+
+def deserialize(JSON, schema, instance):
+    obj_dict = json.loads(JSON)
+    deserialize_from_dict(obj_dict, schema, instance)
+
+class GeneratedObject(Location, Persistent):
+    def __init__(self):
+        pass
+
+class IJSONGenerator(Interface):
+
+    def output(value):
+        """Output value as JSON item according to field.
+        """
+
+    def input(item):
+        """Input JSON item according to field and return value.
+        """
+
+class Text(grok.Adapter):
+    grok.context(IText)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        return value
+
+    def input(self, item):
+        if item is not None:
+            return unicode(item)
+        return None
+
+class Int(grok.Adapter):
+    grok.context(IInt)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        return value
+
+    def input(self, item):
+        return item
+
+class Object(grok.Adapter):
+    grok.context(IObject)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        cd = {}
+        for name, field in getFieldsInOrder(self.context.schema):
+            cd[name] = IJSONGenerator(field).output(field.get(value))
+        return cd
+
+    def input(self, item):
+        instance = GeneratedObject()
+        deserialize_from_dict(item, self.context.schema, instance)
+        return instance
+
+class List(grok.Adapter):
+    grok.context(IList)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        lst = []
+        field = self.context.value_type
+        for v in value:
+            lst.append(IJSONGenerator(field).output(v))
+        return lst
+
+    def input(self, item):
+        field = self.context.value_type
+        if item is None:
+            return []
+        return [
+            IJSONGenerator(field).input(sub_item)
+            for sub_item in item]
+
+class Datetime(grok.Adapter):
+    grok.context(IDatetime)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        if value is None:
+            return None
+        else:
+            return value.strftime('%Y-%m-%dT%H:%M:%S')
+
+    def input(self, item):
+        if item is not None:
+            return zope.datetime.parseDatetimetz(item)
+        return None
+
+class Choice(grok.Adapter):
+    grok.context(IChoice)
+    grok.implements(IJSONGenerator)
+    
+    def output(self, value):
+        return value
+
+    def input(self, item):
+        if item is not None:
+            return item
+        return None
+
+# Remember, sets cannot store non-hashables.
+class Set(grok.Adapter):
+    grok.context(ISet)
+    grok.implements(IJSONGenerator)
+
+    def output(self, value):
+        lst = []
+        field = self.context.value_type
+        for v in value:
+            lst.append(IJSONGenerator(field).output(v))
+        return lst
+
+    def input(self, item):
+        field = self.context.value_type
+        if item is None:
+            return set()
+        return set([
+            IJSONGenerator(field).input(sub_item)
+            for sub_item in item])


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/_schema2json.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/configure.zcml
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/configure.zcml	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/configure.zcml	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,8 @@
+<configure
+  xmlns="http://namespaces.zope.org/zope"
+  xmlns:grok="http://namespaces.zope.org/grok">
+
+  <include package="grokcore.component" file="meta.zcml" />
+
+  <grok:grok package="."/>
+</configure>


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/configure.zcml
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/ftesting.zcml
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/ftesting.zcml	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/ftesting.zcml	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,6 @@
+<configure
+   xmlns="http://namespaces.zope.org/zope"
+   >
+  <include package="z3c.schema2json" />
+
+</configure>


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/ftesting.zcml
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/testing.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/testing.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/testing.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,7 @@
+import os
+import z3c.schema2json
+from zope.app.testing.functional import ZCMLLayer
+
+ftesting_zcml = os.path.join(
+    os.path.dirname(z3c.schema2json.__file__), 'ftesting.zcml')
+FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer')


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/testing.py
___________________________________________________________________
Added: svn:eol-style
   + native

Added: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/tests.py
===================================================================
--- Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/tests.py	                        (rev 0)
+++ Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/tests.py	2009-06-28 23:09:57 UTC (rev 101308)
@@ -0,0 +1,13 @@
+import unittest
+
+from zope.app.testing.functional import FunctionalDocFileSuite
+from z3c.schema2json.testing import FunctionalLayer
+
+def test_suite():
+
+    readme = FunctionalDocFileSuite(
+        'README.txt')
+
+    readme.layer = FunctionalLayer
+
+    return unittest.TestSuite([readme])


Property changes on: Sandbox/paulwilson/z3c.schema2json/src/z3c/schema2json/tests.py
___________________________________________________________________
Added: svn:eol-style
   + native



More information about the Checkins mailing list