[Zope3-checkins] CVS: Zope3/lib/python/Zope/Schema - FieldProperty.py:1.4 IField.py:1.10 _Field.py:1.5 __init__.py:1.4 _bootstrapFields.py:1.3
Jim Fulton
jim@zope.com
Mon, 11 Nov 2002 15:24:36 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/Schema
In directory cvs.zope.org:/tmp/cvs-serv15816
Modified Files:
FieldProperty.py IField.py _Field.py __init__.py
_bootstrapFields.py
Log Message:
Added TextLine and Line field types to model the common case of
single-line text.
Added a binding protocol to support fields whos validation or
properties depend on specific instances implementing the fields.
See the doc string for IField.
=== Zope3/lib/python/Zope/Schema/FieldProperty.py 1.3 => 1.4 ===
--- Zope3/lib/python/Zope/Schema/FieldProperty.py:1.3 Wed Sep 11 18:06:41 2002
+++ Zope3/lib/python/Zope/Schema/FieldProperty.py Mon Nov 11 15:24:35 2002
@@ -43,14 +43,16 @@
value = inst.__dict__.get(self.__name, _marker)
if value is _marker:
- value = getattr(self.__field, 'default', _marker)
+ field = self.__field.bind(inst)
+ value = getattr(field, 'default', _marker)
if value is _marker:
raise AttributeError, self.__name
return value
def __set__(self, inst, value):
- self.__field.validate(value)
+ field = self.__field.bind(inst)
+ field.validate(value)
inst.__dict__[self.__name] = value
def __getattr__(self, name):
=== Zope3/lib/python/Zope/Schema/IField.py 1.9 => 1.10 ===
--- Zope3/lib/python/Zope/Schema/IField.py:1.9 Thu Oct 10 18:17:57 2002
+++ Zope3/lib/python/Zope/Schema/IField.py Mon Nov 11 15:24:35 2002
@@ -17,15 +17,66 @@
"""
from Interface import Interface
-from _bootstrapFields import Field, Text, Bool, Int, Container, Iteratable
+from _bootstrapFields \
+ import Field, Text, TextLine, Bool, Int, Container, Iteratable
class IField(Interface):
u"""Fields
- Fields are attribute specifications.
+ Fields are attribute specifications. They specify the allowed
+ values for object attributes, Field are typically defined in an
+ interface.
+
+ XXX We need to think aboyt the following
+
+ Note that many field need information about the object
+ implementing 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 meanss that the field needs to
+ have access to the object when performing validation.
+
+ We haven't really decided on the best way to approach providing
+ access to objects in field methods and properties. We've thought
+ of three approaches:
+
+ 1. Always pass the object:
+
+ field.validate(value, object)
+
+ 2. Bind the field to the object with a context wrapper:
+
+ field = ContextWrapper(field, object)
+ field.validate(value)
+
+ 3. Provide a specialized binding protocol:
+
+ bound = field(object_
+ bound.validate(value)
+
+ Options 2 and 3 allow us to use properties, but require an extra
+ binding step.
+
+ Option 1 and 3 will require a significant refactoring.
+
+ Option 2 requires us to make field methods, or at least the
+ validate method into ContextMethods, which is a bit intrusive.
+
+ For now, we will use option 3.
+
"""
- title = Text(
+ def bind(object):
+ """Bind the field to an object
+
+ This is done by returning a copy of the field with a "context"
+ attribute set to the object.
+
+ Many fields don't need to be bound. Only fields that condition
+ validation or properties on an object containing the field
+ need to be bound.
+ """
+
+ title = TextLine(
title=u"Title",
description=u"A short summary or label",
default=u"",
@@ -159,10 +210,16 @@
u"""Describes the footprint of a Bool variable."""
class IBytes(ISized, IEnumeratable, IIteratable):
- u"""Describes the footprint of a Bytes variable."""
+ u"""Describes the footprint of a Bytes variable"""
+
+class ILine(IBytes):
+ u"""Describes the footprint of a Bytes variable withouit newlines"""
class IText(ISized, IEnumeratable, IIteratable):
- u"""Describes the footprint of a Str variable."""
+ u"""Describes the footprint of a Text variable."""
+
+class ITextLine(IText):
+ u"""Describes the footprint of a one-line Text variable."""
class IInt(IEnumeratable, IOrderable):
u"""Describes the footprint of an Int variable."""
=== Zope3/lib/python/Zope/Schema/_Field.py 1.4 => 1.5 ===
--- Zope3/lib/python/Zope/Schema/_Field.py:1.4 Fri Oct 4 14:24:55 2002
+++ Zope3/lib/python/Zope/Schema/_Field.py Mon Nov 11 15:24:35 2002
@@ -24,7 +24,7 @@
import IField
from _bootstrapFields import Field, Container, Iteratable, Orderable, Sized
-from _bootstrapFields import Enumeratable, Text, Bool, Int
+from _bootstrapFields import Enumeratable, Text, TextLine, Bool, Int
from FieldProperty import FieldProperty
from datetime import datetime
@@ -47,6 +47,7 @@
implements(Enumeratable, IField.IEnumeratable)
implements(Text, IField.IText)
+implements(TextLine, IField.ITextLine)
implements(Bool, IField.IBool)
implements(Int, IField.IInt)
@@ -55,6 +56,16 @@
__implements__ = IField.IBytes
_type = str
+
+class Line(Bytes):
+ """A Text field with no newlines."""
+
+ __implements__ = IField.ILine
+
+ def constraint(self, value):
+ # XXX we should probably use a more general definition of newlines
+ return '\n' not in value
+
class Float(Enumeratable, Orderable):
__doc__ = IField.IFloat.__doc__
=== Zope3/lib/python/Zope/Schema/__init__.py 1.3 => 1.4 ===
--- Zope3/lib/python/Zope/Schema/__init__.py:1.3 Fri Oct 4 14:24:55 2002
+++ Zope3/lib/python/Zope/Schema/__init__.py Mon Nov 11 15:24:35 2002
@@ -18,5 +18,6 @@
from _Field import Field, Container, Iteratable, Orderable, Sized, Enumeratable
from _Field import Sequence
-from _Field import Bytes, Text, Bool, Int, Float, Tuple, List, Dict, Datetime
+from _Field import Bytes, Line, Text, TextLine, Bool, Int, Float
+from _Field import Tuple, List, Dict, Datetime
from _Schema import validateMapping, validateMappingAll, getFields
=== Zope3/lib/python/Zope/Schema/_bootstrapFields.py 1.2 => 1.3 ===
--- Zope3/lib/python/Zope/Schema/_bootstrapFields.py:1.2 Wed Sep 18 11:05:51 2002
+++ Zope3/lib/python/Zope/Schema/_bootstrapFields.py Mon Nov 11 15:24:35 2002
@@ -64,13 +64,19 @@
self.description = description
self.required = required
self.readonly = readonly
- self.constraint = constraint
+ if constraint is not None:
+ self.constraint = constraint
self.default = default
# Keep track of the order of field definition
Field.order += 1
self.order = Field.order
+ def bind(self, object):
+ clone = self.__class__.__new__(self.__class__)
+ clone.__dict__.update(self.__dict__)
+ clone.context = object
+ return clone
def validate(self, value):
if value is None:
@@ -196,9 +202,10 @@
# Set allowed_values to None so that we can validate if
# one of the super methods invoke validation.
- self.allowed_values = None
+ self.__dict__['allowed_values'] = None
super(Enumeratable, self).__init__(**kw)
- self.allowed_values = allowed_values
+ if allowed_values is not None:
+ self.allowed_values = allowed_values
# We've taken over setting default so it can be limited by min
# and max.
@@ -209,12 +216,22 @@
if self.allowed_values:
if not value in self.allowed_values:
- raise ValidationError(ErrorNames.InvalidValue)
+ raise ValidationError(ErrorNames.InvalidValue, value,
+ self.allowed_values)
class Text(Sized, Enumeratable):
- """A field representing a Str."""
+ """A field containing text used for human discourse."""
_type = unicode
+
+
+class TextLine(Text):
+ """A Text field with no newlines."""
+
+ def constraint(self, value):
+ # XXX we should probably use a more general definition of newlines
+ return '\n' not in value
+
class Bool(Field):
"""A field representing a Bool."""