[Zope3-checkins] CVS: Zope3/lib/python/Zope/Schema - IField.py:1.12 _Field.py:1.7 __init__.py:1.5 _bootstrapFields.py:1.5

Holger Krekel hpk@devel.trillke.net
Thu, 5 Dec 2002 08:27:08 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/Schema
In directory cvs.zope.org:/tmp/cvs-serv27419/lib/python/Zope/Schema

Modified Files:
	IField.py _Field.py __init__.py _bootstrapFields.py 
Log Message:
- refactored/renamed the fields in IField.py interfaces 
  together with Martijn Faassen to have expressive and
  consistent names.

- please note that now the 'required' field defaults
  to true. you have to explicitly state that you 
  want a Field to be optional (i.e. non-required).

- improved the docstrings

- modified the unittests to reflect the new situation



=== Zope3/lib/python/Zope/Schema/IField.py 1.11 => 1.12 ===
--- Zope3/lib/python/Zope/Schema/IField.py:1.11	Tue Nov 12 07:33:15 2002
+++ Zope3/lib/python/Zope/Schema/IField.py	Thu Dec  5 08:27:06 2002
@@ -18,19 +18,25 @@
 from Interface import Interface
 
 from _bootstrapFields \
-     import Field, Text, TextLine, Bool, Int, Container, Iteratable
+     import Field, Text, TextLine, Bool, Int, Container, Iterable
 
 class IField(Interface):
-    u"""Fields
+    """Basic Schema Field Interface.
 
-    Fields are attribute specifications. They specify the allowed
-    values for object attributes, Field are typically defined in an
-    interface. 
-
-    XXX We need to think about the following
+    Fields are used for Interface specifications.  They at least provide 
+    a title, description and a default value.  You can also
+    specify if they are required and/or readonly.  
+
+    The Field Interface is also used for validation and specifying 
+    constraints. 
+ 
+    We want to make it possible for a IField to not only work
+    on its value but also on the object this value is bound to.  
+    This enables a Field implementation to perform validation
+    against an object which also marks a certain place. 
     
     Note that many fields need information about the object
-    implementing a field. For example, when validating a value to be
+    containing a field. For example, when validating a value to be
     set as an object attribute, it may be necessary for the field to
     introspect the object's state. This means that the field needs to
     have access to the object when performing validation.
@@ -50,7 +56,7 @@
 
     3. Provide a specialized binding protocol:
 
-         bound = field(object)
+         bound = field.bind(object)
          bound.validate(value)
 
     Options 2 and 3 allow us to use properties, but require an extra
@@ -66,10 +72,11 @@
     """
 
     def bind(object):
-        """Bind the field to an object
+        """return a copy of this field which is bound to an object. 
 
-        This is done by returning a copy of the field with a "context"
-        attribute set to the object.
+        The copy of the Field will have the 'context' attribute set
+        to 'object'.  This way a Field can implement more complex 
+        checks involving the object and its location. 
 
         Many fields don't need to be bound. Only fields that condition
         validation or properties on an object containing the field
@@ -93,33 +100,38 @@
     required = Bool(
         title=u"Required",
         description=(
-        u"An indication of whether the field value must be provided"),
+        u"tells whether a field requires its value to exist."),
         default=True)
 
     readonly = Bool(
-        title="uRead Only",
+        title=u"Read Only",
         description=u"Read-only.", # XXX what is this?
+        required=False,
         default=False)
 
     default = Field(
-        title=u"The default field value",
+        title=u"default field value if no value is present",
         description=u"""The field default value may be None or a legal
                         field value"""
         )
 
     def constraint(value):
-        u"""Optional vaue constraint
-
-        Returns true is the value is legal, and false otherwise.
+        u"""check a customized contraint on the value. 
 
-        This is typically specified as a constructor argument.
+        You can implement this method with your Field to 
+        require a certain constraint.  This relaxes the need
+        to inherit/subclass a Field you to add a simple contraint. 
+        Returns true if the given value is within the Field's contraint.
         """
 
     def validate(value):
-        u"""Validate that the given value is a valid field entry.
+        u"""Validate that the given value is a valid field value.
 
         Returns nothing but raises an error if the value is invalid.
+        It checks everything specific to a Field and also checks
+        with the additional constraint. 
         """
+
     order = Int(
         title=u"Field Order",
         description=u"""\
@@ -134,43 +146,52 @@
         readonly=True,
         )
 
-class IContainer(IField):
-    u"""Fields with values that allow containment checks using the in operator
 
-    Values include sequences, iteratorable objects, and any objects
-    that implement __contains__.
+class IIterable(IField):
+    u"""Fields with a value that can be iterated over.
+
+    The value needs to follow the python __iter__ protocol. 
     """
 
-class IIteratable(IContainer):
-    u"""Fields with value that can be iterated over
+class IContainer(IField):
+    u"""Fields whose value allows an 'x in value' check. 
+
+    The Value needs to have a conventional __contains__ method. 
     """
 
 class IOrderable(IField):
-    u"""Orderable values
+    u"""a Field requiring its value to be orderable.
 
-    They can be restricted to a range of values by specifying a
-    minimum and maximum value.
+    The value needs to have a conventional __cmp__ method. 
+    """
+
+class ILen(IField):
+    u"""a Field requiring its value to have a length. 
+
+    The value needs to have a conventional __len__ method.
+    """
+
+class IMinMax(IOrderable):
+    u"""a Field requiring its value to be between min and max. 
+    
+    This also means that the value needs to support the IOrderable interface.
     """
 
     min = Field(
-        title=u"The minimum allowable value",
-        description=u"""\
-        If this value is not None, then it must be a legal field value
-        and all field values must be less than this value.        
-        """
+        title=u"Start of the range",
+        required=False,
+        default=None
         )
 
     max = Field(
-        title=u"The maximum allowable value",
-        description=u"""\
-        If this value is not None, then it must be a legal field value
-        and all field values must be greater than this value.        
-        """
+        title=u"End of the range (excluding the value itself)",
+        required=False,
+        default=None
         )
+    
 
-class ISized(IField):
-    u"""Sized objects may have a minimum and maximum length
-    """
+class IMinMaxLen(ILen):
+    u"""a Field requiring the length of its value to be within a range"""
     
     min_length = Int(
         title=u"Minimum length",
@@ -179,7 +200,7 @@
         min_length characters. If min_length is None, there is 
         no minimum.
         """,
-        required=0,
+        required=False,
         min=0, # needs to be a positive number
         default=0)
 
@@ -189,14 +210,12 @@
         Value after whitespace processing cannot have greater
         or equal than max_length characters. If max_length is
         None, there is no maximum.""",
-        required=0,
+        required=False,
         min=0, # needs to be a positive number
         default=None)
 
-
-class IEnumeratable(IField):
-    u"""Fields with values that may be constrained to a set of values
-    """
+class IValueSet(IField):
+    u"""Field whose value is contained in a predefined set"""
     
     allowed_values = Container(
         title=u"Allowed Values",
@@ -204,31 +223,35 @@
         Only values specified here can be values of this field.
         If the list is empty, then there are no further
         restictions.""",
-        required=0)
+        required=False)
             
 class IBool(IField):
-    u"""Describes the footprint of a Bool variable."""
+    u"""a Boolean Field."""
+
+class IBytes(IMinMaxLen, IValueSet, IIterable):
+    u"""a Field containing a byte string (like the python str).
 
-class IBytes(ISized, IEnumeratable, IIteratable):
-    u"""Describes the footprint of a Bytes variable"""
+    The value might be contrained to be with length limits, or 
+    be within a set of values. 
+    """
 
-class ILine(IBytes):
-    u"""Describes the footprint of a Bytes variable without newlines"""
+class IBytesLine(IBytes):
+    u"""a Field containing a byte string without newlines."""
 
-class IText(ISized, IEnumeratable, IIteratable):
-    u"""Describes the footprint of a Text variable."""
+class IText(IMinMaxLen, IValueSet, IIterable):
+    u"""a Field containing a unicode string."""
 
 class ITextLine(IText):
-    u"""Describes the footprint of a one-line Text variable."""
+    u"""a Field containing a unicode string without newlines."""
     
-class IInt(IEnumeratable, IOrderable):
-    u"""Describes the footprint of an Int variable."""
+class IInt(IMinMax, IValueSet):
+    u"""a Field containing an Integer Value."""
         
-class IFloat(IEnumeratable, IOrderable):
-    u"""Describes the footprint of a Float variable."""
+class IFloat(IMinMax, IValueSet):
+    u"""a Field containing a Float."""
         
-class IDatetime(IEnumeratable, IOrderable):
-    u"""Describes the footprint of a datetime variable."""
+class IDatetime(IMinMax, IValueSet):
+    u"""a Field containing a DateTime."""
 
 def _fields(values):
     for value in values:
@@ -236,45 +259,47 @@
             return False
     return True
 
-class ISequence(ISized, IIteratable):
-    u"""Describes fields that can hold a sequence values
+class ISequence(IMinMaxLen, IIterable):
+    u"""a Field containing a Sequence value.
 
-    These values may be constrained.
+    The Value must be iterable and may have a min_length/max_length.
     """
 
-    value_types = Iteratable(
+    value_types = Iterable(
         title=u"Value Types",
         description=(
         u"""\
         If set to a non-empty value, field value items must conform to one
         of the given types, which are expressed via fields.
         """),
-        required=0,
+        required=False,
         constraint=_fields,
         )
 
-
 class ITuple(ISequence):
-    u"""Describes the footprint of a Tuple variable."""
+    u"""a Field containing a conventional tuple."""
 
 class IList(ISequence):
-    u"""Describes the footprint of a List variable."""
+    u"""a Field containing a conventional list."""
 
+class IDict(IMinMaxLen, IIterable):
+    u"""a Field containing a conventional dict.
 
-class IDict(ISized, IIteratable):
-    u"""Describes the footprint of a Dict variable."""
+    the key_types and value_types field allow specification
+    of restrictions for the dict.
+    """
 
-    key_types = Iteratable(
+    key_types = Iterable(
         title=u"Value Types",
         description=u"""\
         If set to a non-empty value, field value keys must conform to one
         of the given types, which are expressed via fields.
         """,
         constraint=_fields,
-        required=0,
+        required=False,
         )
 
-    value_types = Iteratable(
+    value_types = Iterable(
         title=u"Value Types",
         description=(
         u"""\
@@ -282,5 +307,5 @@
         of the given types, which are expressed via fields.
         """),
         constraint=_fields,
-        required=0,
+        required=False,
         )


=== Zope3/lib/python/Zope/Schema/_Field.py 1.6 => 1.7 ===
--- Zope3/lib/python/Zope/Schema/_Field.py:1.6	Mon Nov 18 08:20:44 2002
+++ Zope3/lib/python/Zope/Schema/_Field.py	Thu Dec  5 08:27:06 2002
@@ -22,8 +22,8 @@
 import ErrorNames
 
 import IField
-from _bootstrapFields import Field, Container, Iteratable, Orderable, Sized
-from _bootstrapFields import Enumeratable, Text, TextLine, Bool, Int
+from _bootstrapFields import Field, Container, Iterable, Orderable, MinMaxLen
+from _bootstrapFields import ValueSet, Text, TextLine, Bool, Int
 from FieldProperty import FieldProperty
 from datetime import datetime
 
@@ -36,21 +36,21 @@
 implements(Field, IField.IField)
 
 implements(Container, IField.IContainer)
-implements(Iteratable, IField.IIteratable)
+implements(Iterable, IField.IIterable)
 implements(Orderable, IField.IOrderable)
 
-Sized.min_length = FieldProperty(IField.ISized['min_length'])
-Sized.max_length = FieldProperty(IField.ISized['max_length'])
-implements(Sized, IField.ISized)
+MinMaxLen.min_length = FieldProperty(IField.IMinMaxLen['min_length'])
+MinMaxLen.max_length = FieldProperty(IField.IMinMaxLen['max_length'])
+implements(MinMaxLen, IField.IMinMaxLen)
 
-implements(Enumeratable, IField.IEnumeratable)
+implements(ValueSet, IField.IValueSet)
 
 implements(Text, IField.IText)
 implements(TextLine, IField.ITextLine)
 implements(Bool, IField.IBool)
 implements(Int, IField.IInt)
             
-class Bytes(Sized, Enumeratable):
+class Bytes(MinMaxLen, ValueSet):
     __doc__ = IField.IBytes.__doc__
     __implements__ = IField.IBytes
     
@@ -59,19 +59,19 @@
 class Line(Bytes):
     """A Text field with no newlines."""
 
-    __implements__ = IField.ILine
+    __implements__ = IField.IBytesLine
 
     def constraint(self, value):
         # XXX we should probably use a more general definition of newlines
         return '\n' not in value
     
 
-class Float(Enumeratable, Orderable):
+class Float(ValueSet, Orderable):
     __doc__ = IField.IFloat.__doc__
     __implements__ = IField.IFloat
     _type = float
 
-class Datetime(Enumeratable, Orderable):
+class Datetime(ValueSet, Orderable):
     __doc__ = IField.IDatetime.__doc__
     __implements__ = IField.IDatetime
     _type = datetime
@@ -84,9 +84,7 @@
         return errors
 
     for item in value:
-
         error = None
-
         for t in value_types:
             try:
                 t.validate(item)
@@ -104,7 +102,7 @@
     return errors
     
 
-class Sequence(Sized, Iteratable):
+class Sequence(MinMaxLen, Iterable):
     __doc__ = IField.ISequence.__doc__
     value_types = FieldProperty(IField.ISequence['value_types'])
 
@@ -132,7 +130,7 @@
     __implements__ = IField.IList
     _type = list
 
-class Dict(Sized, Iteratable):
+class Dict(MinMaxLen, Iterable):
     """A field representing a Dict."""
     __implements__ = IField.IDict
     _type = dict


=== Zope3/lib/python/Zope/Schema/__init__.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/Schema/__init__.py:1.4	Mon Nov 11 15:24:35 2002
+++ Zope3/lib/python/Zope/Schema/__init__.py	Thu Dec  5 08:27:06 2002
@@ -16,7 +16,7 @@
 $Id$
 """
 
-from _Field import Field, Container, Iteratable, Orderable, Sized, Enumeratable
+from _Field import Field, Container, Iterable, Orderable, MinMaxLen, ValueSet
 from _Field import Sequence
 from _Field import Bytes, Line, Text, TextLine, Bool, Int, Float
 from _Field import Tuple, List, Dict, Datetime


=== Zope3/lib/python/Zope/Schema/_bootstrapFields.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/Schema/_bootstrapFields.py:1.4	Wed Dec  4 05:00:56 2002
+++ Zope3/lib/python/Zope/Schema/_bootstrapFields.py	Thu Dec  5 08:27:06 2002
@@ -46,7 +46,7 @@
     
     def __init__(self, __name__='', __doc__='',
                  title=u'', description=u'',
-                 required=False, readonly=False, constraint=None, default=None,
+                 required=True, readonly=False, constraint=None, default=None,
                  ):
         """Pass in field values as keyword parameters."""
 
@@ -110,10 +110,10 @@
                 raise ValidationError(ErrorNames.NotAContainer, value)
                 
                 
-class Iteratable(Container):
+class Iterable(Container):
 
     def _validate(self, value):
-        super(Iteratable, self)._validate(value)
+        super(Iterable, self)._validate(value)
 
         # See if we can get an iterator for it
         try:
@@ -159,17 +159,17 @@
             raise ValidationError(ErrorNames.TooBig, value, self.max)
 
 _int_types = int, long
-class Sized(Field):
+class MinMaxLen(Field):
     min_length = 0
     max_length = None
 
     def __init__(self, min_length=0, max_length=None, **kw):
         self.min_length = min_length
         self.max_length = max_length
-        super(Sized, self).__init__(**kw)
+        super(MinMaxLen, self).__init__(**kw)
 
     def _validate(self, value):
-        super(Sized, self)._validate(value)
+        super(MinMaxLen, self)._validate(value)
 
         if self.min_length is not None and len(value) < self.min_length:
             raise ValidationError(ErrorNames.TooShort, value, self.min_length)
@@ -178,7 +178,7 @@
             raise ValidationError(ErrorNames.TooLong, value, self.max_length)
         
 
-class Enumeratable(Field):
+class ValueSet(Field):
 
     def allowed_values(self, values):
         # Reset current value so it doesn't hose validation
@@ -204,7 +204,7 @@
         # Set allowed_values to None so that we can validate if
         # one of the super methods invoke validation.
         self.__dict__['allowed_values'] = None
-        super(Enumeratable, self).__init__(**kw)
+        super(ValueSet, self).__init__(**kw)
         if allowed_values is not None:
             self.allowed_values = allowed_values
 
@@ -213,7 +213,7 @@
         self.default = default
 
     def _validate(self, value):
-        super(Enumeratable, self)._validate(value)
+        super(ValueSet, self)._validate(value)
 
         if self.allowed_values:
             if not value in self.allowed_values:
@@ -221,7 +221,7 @@
                                       self.allowed_values)
 
 
-class Text(Sized, Enumeratable):
+class Text(MinMaxLen, ValueSet):
     """A field containing text used for human discourse."""
     _type = unicode
     
@@ -247,6 +247,6 @@
     else:
         _type = bool
 
-class Int(Enumeratable, Orderable):
+class Int(ValueSet, Orderable):
     """A field representing a Integer."""
     _type = int, long