[Zope3-checkins] SVN: Zope3/trunk/src/zope/schema/ - added
context-sensitive sources with tests
Benji York
benji at zope.com
Fri Sep 2 15:25:40 EDT 2005
Log message for revision 38246:
- added context-sensitive sources with tests
- also added a test for non-context-sensitive sources
Changed:
U Zope3/trunk/src/zope/schema/_field.py
U Zope3/trunk/src/zope/schema/interfaces.py
A Zope3/trunk/src/zope/schema/sources.txt
U Zope3/trunk/src/zope/schema/tests/test_docs.py
-=-
Modified: Zope3/trunk/src/zope/schema/_field.py
===================================================================
--- Zope3/trunk/src/zope/schema/_field.py 2005-09-02 14:01:19 UTC (rev 38245)
+++ Zope3/trunk/src/zope/schema/_field.py 2005-09-02 19:25:40 UTC (rev 38246)
@@ -34,6 +34,7 @@
from zope.schema.interfaces import IPassword, IObject, IDate, ITimedelta
from zope.schema.interfaces import IURI, IId, IFromUnicode
from zope.schema.interfaces import ISource, IBaseVocabulary
+from zope.schema.interfaces import IContextSourceBinder
from zope.schema.interfaces import ValidationError, InvalidValue
from zope.schema.interfaces import WrongType, WrongContainedType, NotUnique
@@ -196,7 +197,6 @@
assert source is None, (
"You cannot specify both source and vocabulary.")
elif source is not None:
- assert ISource.providedBy(source)
vocabulary = source
assert not (values is None and vocabulary is None), (
@@ -211,7 +211,8 @@
elif isinstance(vocabulary, (unicode, str)):
self.vocabularyName = vocabulary
else:
- assert ISource.providedBy(vocabulary)
+ assert (ISource.providedBy(vocabulary) or
+ IContextSourceBinder.providedBy(vocabulary))
self.vocabulary = vocabulary
# Before a default value is checked, it is validated. However, a
# named vocabulary is usually not complete when these fields are
@@ -228,9 +229,14 @@
"""See zope.schema._bootstrapinterfaces.IField."""
clone = super(Choice, self).bind(object)
# get registered vocabulary if needed:
- if clone.vocabulary is None and self.vocabularyName is not None:
+ if IContextSourceBinder.providedBy(self.vocabulary):
+ clone.vocabulary = self.vocabulary(object)
+ assert ISource.providedBy(clone.vocabulary)
+ elif clone.vocabulary is None and self.vocabularyName is not None:
vr = getVocabularyRegistry()
clone.vocabulary = vr.get(object, self.vocabularyName)
+ assert ISource.providedBy(clone.vocabulary)
+
return clone
def fromUnicode(self, str):
Modified: Zope3/trunk/src/zope/schema/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/schema/interfaces.py 2005-09-02 14:01:19 UTC (rev 38245)
+++ Zope3/trunk/src/zope/schema/interfaces.py 2005-09-02 19:25:40 UTC (rev 38246)
@@ -498,6 +498,11 @@
searcing for items.
"""
+
+class IContextSourceBinder(Interface):
+ def __call__(context):
+ """Return a context-bound instance that implements ISource.
+ """
# TODO, define iterable sources. For now, we'll just use vocabularies.
Added: Zope3/trunk/src/zope/schema/sources.txt
===================================================================
--- Zope3/trunk/src/zope/schema/sources.txt 2005-09-02 14:01:19 UTC (rev 38245)
+++ Zope3/trunk/src/zope/schema/sources.txt 2005-09-02 19:25:40 UTC (rev 38246)
@@ -0,0 +1,49 @@
+=================
+Sources in Fields
+=================
+
+A choice field can be constructed with a source or source name. When a source
+is used, it will be used as the source for valid values.
+
+Create a source for all odd numbers.
+
+ >>> from zope import interface
+ >>> from zope.schema.interfaces import ISource, IContextSourceBinder
+ >>> class MySource(object):
+ ... interface.implements(ISource)
+ ... divisor = 2
+ ... def __contains__(self, value):
+ ... return bool(value % self.divisor)
+ >>> my_source = MySource()
+ >>> 1 in my_source
+ True
+ >>> 2 in my_source
+ False
+
+ >>> from zope.schema import Choice
+ >>> choice = Choice(__name__='number', source=my_source)
+ >>> bound = choice.bind(object())
+ >>> bound.vocabulary
+ <...MySource...>
+
+If a IContextSourceBinder is passed as the `source` argument to Choice, it's
+`bind` method will be called with the context as its only argument. The
+result must implement ISource and will be used as the source.
+
+ >>> def my_binder(context):
+ ... print "Binder was called."
+ ... source = MySource()
+ ... source.divisor = context.divisor
+ ... return source
+ >>> interface.directlyProvides(my_binder, IContextSourceBinder)
+
+ >>> class Context(object):
+ ... divisor = 3
+
+ >>> choice = Choice(__name__='number', source=my_binder)
+ >>> bound = choice.bind(Context())
+ Binder was called.
+ >>> bound.vocabulary
+ <...MySource...>
+ >>> bound.vocabulary.divisor
+ 3
Property changes on: Zope3/trunk/src/zope/schema/sources.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Modified: Zope3/trunk/src/zope/schema/tests/test_docs.py
===================================================================
--- Zope3/trunk/src/zope/schema/tests/test_docs.py 2005-09-02 14:01:19 UTC (rev 38245)
+++ Zope3/trunk/src/zope/schema/tests/test_docs.py 2005-09-02 19:25:40 UTC (rev 38246)
@@ -20,6 +20,7 @@
def test_suite():
return unittest.TestSuite((
+ doctest.DocFileSuite('../sources.txt', optionflags=doctest.ELLIPSIS),
doctest.DocFileSuite('../README.txt'),
))
More information about the Zope3-Checkins
mailing list