[Checkins] SVN: zope.schema/branches/faassen-transformer/src/zope/schema/ Some code to help with transforming interfaces to other ones.
Martijn Faassen
faassen at startifact.com
Thu Feb 4 13:09:18 EST 2010
Log message for revision 108775:
Some code to help with transforming interfaces to other ones.
Changed:
U zope.schema/branches/faassen-transformer/src/zope/schema/__init__.py
A zope.schema/branches/faassen-transformer/src/zope/schema/_transformer.py
U zope.schema/branches/faassen-transformer/src/zope/schema/tests/test_docs.py
A zope.schema/branches/faassen-transformer/src/zope/schema/transformer.txt
-=-
Modified: zope.schema/branches/faassen-transformer/src/zope/schema/__init__.py
===================================================================
--- zope.schema/branches/faassen-transformer/src/zope/schema/__init__.py 2010-02-04 18:06:39 UTC (rev 108774)
+++ zope.schema/branches/faassen-transformer/src/zope/schema/__init__.py 2010-02-04 18:09:18 UTC (rev 108775)
@@ -29,5 +29,6 @@
getValidationErrors, getSchemaValidationErrors)
from zope.schema.accessors import accessors
from zope.schema.interfaces import ValidationError
+from zope.schema._transformer import transformer
__all__ = tuple(name for name in globals() if not name.startswith('_'))
Added: zope.schema/branches/faassen-transformer/src/zope/schema/_transformer.py
===================================================================
--- zope.schema/branches/faassen-transformer/src/zope/schema/_transformer.py (rev 0)
+++ zope.schema/branches/faassen-transformer/src/zope/schema/_transformer.py 2010-02-04 18:09:18 UTC (rev 108775)
@@ -0,0 +1,57 @@
+from zope.interface.interface import InterfaceClass
+from zope.schema import getFieldNamesInOrder
+
+class transformer(object):
+ def __init__(self, schema):
+ self.schema = schema
+
+ def select(self, names):
+ attrs = {}
+ order = 0
+ for name in names:
+ attrs[name] = self._copy_field(self.schema[name],
+ order=order)
+ order += 1
+
+ return transformer(InterfaceClass(name=self.schema.__name__,
+ bases=self.schema.__bases__,
+ __module__=self.schema.__module__,
+ attrs=attrs))
+
+ def omit(self, names):
+ attrs = {}
+ order = 0
+ for name in getFieldNamesInOrder(self.schema):
+ if name not in names:
+ attrs[name] = self._copy_field(self.schema[name],
+ order=order)
+ order += 1
+
+ return transformer(InterfaceClass(name=self.schema.__name__,
+ bases=self.schema.__bases__,
+ __module__=self.schema.__module__,
+ attrs=attrs))
+
+ def override(self, name, **kw):
+ attrs = {}
+ order = 0
+ for name in getFieldNamesInOrder(self.schema):
+ attrs[name] = self._copy_field(self.schema[name],
+ order=order,
+ **kw)
+ order += 1
+
+ return transformer(InterfaceClass(name=self.schema.__name__,
+ bases=self.schema.__bases__,
+ __module__=self.schema.__module__,
+ attrs=attrs))
+
+
+ def _copy_field(self, field, **kw):
+ # by passing None as context, we can trick the binding
+ # machinery into making a straight copy
+ clone = field.bind(None)
+ for key, value in kw.items():
+ setattr(clone, key, value)
+ return clone
+
Modified: zope.schema/branches/faassen-transformer/src/zope/schema/tests/test_docs.py
===================================================================
--- zope.schema/branches/faassen-transformer/src/zope/schema/tests/test_docs.py 2010-02-04 18:06:39 UTC (rev 108774)
+++ zope.schema/branches/faassen-transformer/src/zope/schema/tests/test_docs.py 2010-02-04 18:09:18 UTC (rev 108775)
@@ -31,6 +31,9 @@
doctest.DocFileSuite(
'../validation.txt', checker=checker,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
+ doctest.DocFileSuite(
+ '../transformer.txt',
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
))
if __name__ == '__main__':
Added: zope.schema/branches/faassen-transformer/src/zope/schema/transformer.txt
===================================================================
--- zope.schema/branches/faassen-transformer/src/zope/schema/transformer.txt (rev 0)
+++ zope.schema/branches/faassen-transformer/src/zope/schema/transformer.txt 2010-02-04 18:09:18 UTC (rev 108775)
@@ -0,0 +1,94 @@
+Transforming schemas
+====================
+
+It is possible to transform schemas into other ones. The transformer
+facility follows the rule that schemas are immutable, but that other
+schemas can be constructed out of old ones.
+
+Let's take a simple schema::
+
+ >>> from zope.interface import Interface
+ >>> from zope import schema
+ >>> class IFoo(Interface):
+ ... a = schema.Int(title=u'A')
+ ... b = schema.TextLine(title=u'B')
+ ... c = schema.TextLine(title=u'C')
+ ... d = schema.Int(title=u'D')
+
+To transform the schema, we first need to wrap it into a transformer::
+
+ >>> from zope.schema import transformer
+ >>> ifoo_transformer = transformer(IFoo)
+
+A transformer has a ``schema`` attribute indicating its schema::
+
+ >>> ifoo_transformer.schema is IFoo
+ True
+
+Transformers define operations, and each returns a transformer. This
+allows these operations to be chained.
+
+Select
+------
+
+We can use the transformer to construct a new schema, selecting only
+``a``, and ``b``::
+
+ >>> selected_transformer = ifoo_transformer.select(['a', 'b'])
+
+Out comes another transformer, with the transformed schema::
+
+ >>> IFooSelect = selected_transformer.schema
+ >>> from zope.schema import getFieldNamesInOrder
+ >>> getFieldNamesInOrder(IFooSelect)
+ ['a', 'b']
+
+We can also reorder the fields in the schema this way::
+
+ >>> reordered_transformer = ifoo_transformer.select(['d', 'c', 'b', 'a'])
+ >>> getFieldNamesInOrder(reordered_transformer.schema)
+ ['d', 'c', 'b', 'a']
+
+We cannot select fields that do not exist::
+
+ >>> ifoo_transformer.select(['z'])
+ Traceback (most recent call last):
+ ...
+ KeyError: 'z'
+
+Omit
+----
+
+We can also omit fields. This results in a new schema without the omitted
+field. The order of the remaining fields is unaffected::
+
+ >>> omitted_transformer = ifoo_transformer.omit(['a'])
+ >>> getFieldNamesInOrder(omitted_transformer.schema)
+ ['b', 'c', 'd']
+
+We are free to omit fields that do not exist, as they aren't there anyway::
+
+ >>> getFieldNamesInOrder(ifoo_transformer.omit(['z']).schema)
+ ['a', 'b', 'c', 'd']
+
+Override
+--------
+
+We can also override field properties. Let's say we want to modify the
+title of the ``a`` field.
+
+The title starts out as ``'A'``:
+
+ >>> IFoo['a'].title
+ u'A'
+
+Now we override the title, producing a new schema::
+
+ >>> schema = ifoo_transformer.override('a', title=u'A overridden').schema
+ >>> schema['a'].title
+ u'A overridden'
+
+You can override any property, and also more than one, by using
+keyword arguments.
+
+
More information about the checkins
mailing list