[Zodb-checkins] CVS: Zope3/src/zope/interface - __init__.py:1.12 interface.py:1.17 interfaces.py:1.20

Gary Poster gary at zope.com
Tue Jan 20 16:18:13 EST 2004


Update of /cvs-repository/Zope3/src/zope/interface
In directory cvs.zope.org:/tmp/cvs-serv28571

Modified Files:
	__init__.py interface.py interfaces.py 
Log Message:
Add a few useful bits.

1) You can now set an invariant in your interface, where an invariant is a
validation constraint on the interface as a whole (as opposed to the individual
field constraints in schema).  The invariant should simply be a callable that
accepts an object claiming to implement the interface, and raises Invalid or a
subclass thereof if the constraint is not met (the eventual intent is to fit
into the "error view" framework, but other systems can work for now).  It is
expected that objects validated by such invariants will work primarily or
exclusively with Attributes (schema fields) rather than method output; as such,
a pattern of validating data without an actual object may simply be to create a
dummy object, update the object's __dict__ with the data values, and have it
validated.

2) A convenience method is now attached to interfaces to aid in the use of
invariants: validateInvariants.  It validates object with all defined
invariants.  If the errors argument is None (the default), the method raises
the first Invalid error; if errors is a list, it appends all errors to the
list, and then raises Invalid with the errors as the first element of the
"args" tuple.

3) Any other tagged data for the interface can now be added by functions within
an interface--see how the invariant function works, and how the __init__ of the
InterfaceClass snarfs up the information.

An obvious goal for this infrastructure will be to integrate it into the schema/forms machinery.



=== Zope3/src/zope/interface/__init__.py 1.11 => 1.12 ===
--- Zope3/src/zope/interface/__init__.py:1.11	Mon Dec  1 11:19:30 2003
+++ Zope3/src/zope/interface/__init__.py	Tue Jan 20 16:17:41 2004
@@ -76,7 +76,7 @@
 _wire()
 del _wire
 
-from zope.interface.interface import Attribute
+from zope.interface.interface import Attribute, invariant
 
 from zope.interface.declarations import providedBy, implementedBy
 from zope.interface.declarations import classImplements, classImplementsOnly


=== Zope3/src/zope/interface/interface.py 1.16 => 1.17 ===
--- Zope3/src/zope/interface/interface.py:1.16	Mon Dec  1 11:19:33 2003
+++ Zope3/src/zope/interface/interface.py	Tue Jan 20 16:17:41 2004
@@ -22,9 +22,21 @@
 import weakref
 from types import FunctionType
 from ro import ro
+from zope.interface.exceptions import Invalid
 
 CO_VARARGS = 4
 CO_VARKEYWORDS = 8
+TAGGED_DATA = '__interface_tagged_values__'
+
+def invariant(call):
+    f_locals = sys._getframe(1).f_locals
+    tags = f_locals.get(TAGGED_DATA)
+    if tags is None:
+        tags = f_locals[TAGGED_DATA] = {}
+    invariants = tags.get('invariants')
+    if invariants is None:
+        invariants = tags['invariants'] = []
+    invariants.append(call)
 
 class Element(object):
 
@@ -369,6 +381,11 @@
             __doc__ = ''
 
         Element.__init__(self, name, __doc__)
+        
+        tagged_data = attrs.pop(TAGGED_DATA, None)
+        if tagged_data is not None:
+            for key, val in tagged_data.items():
+                self.setTaggedValue(key, val)
 
         for b in bases:
             if not isinstance(b, InterfaceClass):
@@ -490,6 +507,21 @@
         self._deferred=klass
 
         return klass
+
+    def validateInvariants(self, obj, errors=None):
+        """validate object to defined invariants."""
+        for call in self.queryTaggedValue('invariants', []):
+            try:
+                call(obj)
+            except Invalid, e:
+                if errors is None:
+                    raise
+                else:
+                    errors.append(e)
+        for base in self.__bases__:
+            base.validateInvariants(obj, errors)
+        if errors:
+            raise Invalid(errors)
 
     def _getInterface(self, ob, name):
         """Retrieve a named interface."""


=== Zope3/src/zope/interface/interfaces.py 1.19 => 1.20 ===
--- Zope3/src/zope/interface/interfaces.py:1.19	Mon Jan  5 03:07:28 2004
+++ Zope3/src/zope/interface/interfaces.py	Tue Jan 20 16:17:41 2004
@@ -246,6 +246,12 @@
         If the named attribute is not defined, the default is
         returned.
         """
+    
+    def validateInvariants(obj, errors=None):
+        """validate object to defined invariants.  If errors is None,
+        raises first Invalid error; if errors is a list, appends all errors
+        to list, then raises Invalid with the errors as the first element
+        of the "args" tuple."""
 
     def get(name, default=None):
         """Look up the description for a name




More information about the Zodb-checkins mailing list