[Checkins] SVN: zope.schema/branches/tseaver-test_cleanup/ Move doctests to regular Sphinx documentation.

Tres Seaver cvs-admin at zope.org
Fri Apr 20 19:20:54 UTC 2012


Log message for revision 125216:
  Move doctests to regular Sphinx documentation.
  
  You can still test the snippets by running 'make doctest' in the docs subdir.

Changed:
  U   zope.schema/branches/tseaver-test_cleanup/README.txt
  A   zope.schema/branches/tseaver-test_cleanup/docs/fields.rst
  D   zope.schema/branches/tseaver-test_cleanup/docs/index.rst
  A   zope.schema/branches/tseaver-test_cleanup/docs/index.rst
  A   zope.schema/branches/tseaver-test_cleanup/docs/narr.rst
  A   zope.schema/branches/tseaver-test_cleanup/docs/sources.rst
  A   zope.schema/branches/tseaver-test_cleanup/docs/validation.rst
  U   zope.schema/branches/tseaver-test_cleanup/setup.py
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/README.txt
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/fields.txt
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/index.txt
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/sources.txt
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/tests/test_docs.py
  D   zope.schema/branches/tseaver-test_cleanup/src/zope/schema/validation.txt

-=-
Modified: zope.schema/branches/tseaver-test_cleanup/README.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/README.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/README.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -11,4 +11,4 @@
 specify characteristics such as its value being read-only or not
 required.
 
-See 'src/zope/schema/README.txt' for more information.
+See 'docs/index.rst' for more information.

Copied: zope.schema/branches/tseaver-test_cleanup/docs/fields.rst (from rev 125215, zope.schema/branches/tseaver-test_cleanup/src/zope/schema/fields.txt)
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/fields.rst	                        (rev 0)
+++ zope.schema/branches/tseaver-test_cleanup/docs/fields.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -0,0 +1,171 @@
+======
+Fields
+======
+
+This document highlights unusual and subtle aspects of various fields and
+field classes, and is not intended to be a general introduction to schema
+fields.  Please see README.txt for a more general introduction.
+
+While many field types, such as Int, TextLine, Text, and Bool are relatively
+straightforward, a few have some subtlety.  We will explore the general
+class of collections and discuss how to create a custom creation field; discuss
+Choice fields, vocabularies, and their use with collections; and close with a
+look at the standard zope.app approach to using these fields to find views
+("widgets").
+
+Collections
+-----------
+
+Normal fields typically describe the API of the attribute -- does it behave as a
+Python Int, or a Float, or a Bool -- and various constraints to the model, such
+as a maximum or minimum value.  Collection fields have additional requirements
+because they contain other types, which may also be described and constrained.
+
+For instance, imagine a list that contains non-negative floats and enforces
+uniqueness. In a schema, this might be written as follows:
+
+.. doctest::
+
+   >>> from zope.interface import Interface
+   >>> from zope.schema import List, Float
+   >>> from zope.schema._compat import u
+   >>> class IInventoryItem(Interface):
+   ...     pricePoints = List(
+   ...         title=u("Price Points"),
+   ...         unique=True,
+   ...         value_type=Float(title=u("Price"), min=0.0)
+   ...     )
+
+This indicates several things.
+
+- pricePoints is an attribute of objects that implement IInventoryItem.
+- The contents of pricePoints can be accessed and manipulated via a Python list
+  API.
+- Each member of pricePoints must be a non-negative float.
+- Members cannot be duplicated within pricePoints: each must be must be unique.
+- The attribute and its contents have descriptive titles.  Typically these
+  would be message ids.
+
+This declaration creates a field that implements a number of interfaces, among
+them these:
+
+.. doctest::
+
+   >>> from zope.schema.interfaces import IList, ISequence, ICollection
+   >>> IList.providedBy(IInventoryItem['pricePoints'])
+   True
+   >>> ISequence.providedBy(IInventoryItem['pricePoints'])
+   True
+   >>> ICollection.providedBy(IInventoryItem['pricePoints'])
+   True
+
+Creating a custom collection field
+----------------------------------
+
+Ideally, custom collection fields have interfaces that inherit appropriately
+from either zope.schema.interfaces.ISequence or
+zope.schema.interfaces.IUnorderedCollection.  Most collection fields should be
+able to subclass zope.schema._field.AbstractCollection to get the necessary
+behavior.  Notice the behavior of the Set field in zope.schema._field: this
+would also be necessary to implement a Bag.
+
+Choices and Vocabularies
+------------------------
+
+Choice fields are the schema way of spelling enumerated fields and more.  By
+providing a dynamically generated vocabulary, the choices available to a
+choice field can be contextually calculated.  
+
+Simple choices do not have to explicitly use vocabularies:
+
+.. doctest::
+
+   >>> from zope.schema import Choice
+   >>> f = Choice((640, 1028, 1600))
+   >>> f.validate(640)
+   >>> f.validate(960)
+   Traceback (most recent call last):
+   ...
+   ConstraintNotSatisfied: 960
+   >>> f.validate('bing')
+   Traceback (most recent call last):
+   ...
+   ConstraintNotSatisfied: bing
+
+More complex choices will want to use registered vocabularies.  Vocabularies
+have a simple interface, as defined in
+zope.schema.interfaces.IBaseVocabulary.  A vocabulary must minimally be able
+to determine whether it contains a value, to create a term object for a value,
+and to return a query interface (or None) to find items in itself.  Term
+objects are an abstraction that wraps a vocabulary value.  
+
+The Zope application server typically needs a fuller interface that provides
+"tokens" on its terms: ASCII values that have a one-to-one relationship to the
+values when the vocabulary is asked to "getTermByToken".  If a vocabulary is
+small, it can also support the IIterableVocabulary interface.
+
+If a vocabulary has been registered, then the choice merely needs to pass the
+vocabulary identifier to the "vocabulary" argument of the choice during
+instantiation.
+
+A start to a vocabulary implementation that may do all you need for many simple
+tasks may be found in zope.schema.vocabulary.SimpleVocabulary.  Because
+registered vocabularies are simply callables passed a context, many
+registered vocabularies can simply be functions that rely on SimpleVocabulary:
+
+.. doctest::
+
+   >>> from zope.schema.vocabulary import SimpleVocabulary
+   >>> def myDynamicVocabulary(context):
+   ...     v = dynamic_context_calculation_that_returns_an_iterable(context)
+   ...     return SimpleVocabulary.fromValues(v)
+   ... 
+
+The vocabulary interface is simple enough that writing a custom vocabulary is
+not too difficult itself.
+
+See zope.schema.vocabulary.TreeVocabulary for another
+IBaseVocabulary supporting vocabulary that provides a nested, tree-like 
+structure.
+
+Choices and Collections
+-----------------------
+
+Choices are a field type and can be used as a value_type for collections. Just
+as a collection of an "Int" value_type constrains members to integers, so a
+choice-based value type constrains members to choices within the Choice's
+vocabulary.  Typically in the Zope application server widgets are found not
+only for the collection and the choice field but also for the vocabulary on
+which the choice is based.
+
+Using Choice and Collection Fields within a Widget Framework
+------------------------------------------------------------
+
+While fields support several use cases, including code documentation and data
+description and even casting, a significant use case influencing their design is
+to support form generation -- generating widgets for a field.  Choice and
+collection fields are expected to be used within widget frameworks.  The
+zope.app approach typically (but configurably) uses multiple dispatches to 
+find widgets on the basis of various aspects of the fields.
+
+Widgets for all fields are found by looking up a browser view of the field
+providing an input or display widget view.  Typically there is only a single
+"widget" registered for Choice fields.  When it is looked up, it performs
+another dispatch -- another lookup -- for a widget registered for both the field
+and the vocabulary.  This widget typically has enough information to render
+without a third dispatch.
+
+Collection fields may fire several dispatches.  The first is the usual lookup
+by field.  A single "widget" should be registered for ICollection, which does
+a second lookup by field and value_type constraint, if any, or, theoretically,
+if value_type is None, renders some absolutely generic collection widget that
+allows input of any value imaginable: a check-in of such a widget would be
+unexpected.  This second lookup may find a widget that knows how to render,
+and stop.  However, the value_type may be a choice, which will usually fire a
+third dispatch: a search for a browser widget for the collection field, the
+value_type field, and the vocabulary.  Further lookups may even be configured
+on the basis of uniqueness and other constraints.
+
+This level of indirection may be unnecessary for some applications, and can be
+disabled with simple ZCML changes within `zope.app`.
+

Deleted: zope.schema/branches/tseaver-test_cleanup/docs/index.rst
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/index.rst	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/docs/index.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,22 +0,0 @@
-.. zope.schema documentation master file, created by
-   sphinx-quickstart on Fri Apr 20 15:00:47 2012.
-   You can adapt this file completely to your liking, but it should at least
-   contain the root `toctree` directive.
-
-Welcome to zope.schema's documentation!
-=======================================
-
-Contents:
-
-.. toctree::
-   :maxdepth: 2
-
-
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
-

Copied: zope.schema/branches/tseaver-test_cleanup/docs/index.rst (from rev 125215, zope.schema/branches/tseaver-test_cleanup/src/zope/schema/index.txt)
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/index.rst	                        (rev 0)
+++ zope.schema/branches/tseaver-test_cleanup/docs/index.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -0,0 +1,19 @@
+Welcome to zope.schema's documentation!
+=======================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   narr
+   fields
+   sources
+   validation
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`

Copied: zope.schema/branches/tseaver-test_cleanup/docs/narr.rst (from rev 125215, zope.schema/branches/tseaver-test_cleanup/src/zope/schema/README.txt)
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/narr.rst	                        (rev 0)
+++ zope.schema/branches/tseaver-test_cleanup/docs/narr.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -0,0 +1,298 @@
+==============
+Zope 3 Schemas
+==============
+
+Introduction
+------------
+
+*This package is intended to be independently reusable in any Python
+project. It is maintained by the* `Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
+
+Schemas extend the notion of interfaces to detailed descriptions of Attributes
+(but not methods). Every schema is an interface and specifies the public
+fields of an object. A *field* roughly corresponds to an attribute of a
+python object. But a Field provides space for at least a title and a
+description. It can also constrain its value and provide a validation method.
+Besides you can optionally specify characteristics such as its value being
+read-only or not required.
+
+Zope 3 schemas were born when Jim Fulton and Martijn Faassen thought
+about Formulator for Zope 3 and ``PropertySets`` while at the `Zope 3
+sprint`_ at the Zope BBQ in Berlin. They realized that if you strip
+all view logic from forms then you have something similar to interfaces. And
+thus schemas were born.
+
+.. _Zope 3 sprint: http://dev.zope.org/Zope3/ZopeBBQ2002Sprint
+
+.. contents::
+
+Simple Usage
+------------
+
+Let's have a look at a simple example. First we write an interface as usual,
+but instead of describing the attributes of the interface with ``Attribute``
+instances, we now use schema fields:
+
+.. doctest::
+
+   >>> import zope.interface
+   >>> import zope.schema
+   >>> from zope.schema._compat import u, b
+
+   >>> class IBookmark(zope.interface.Interface):
+   ...     title = zope.schema.TextLine(
+   ...         title=u('Title'),
+   ...         description=u('The title of the bookmark'),
+   ...         required=True)
+   ...
+   ...     url = zope.schema.URI(
+   ...         title=u('Bookmark URL'),
+   ...         description=u('URL of the Bookmark'),
+   ...         required=True)
+   ...
+
+Now we create a class that implements this interface and create an instance of
+it:
+
+.. doctest::
+
+   >>> @zope.interface.implementer(IBookmark)
+   ... class Bookmark(object):
+   ...
+   ...     title = None
+   ...     url = None
+
+   >>> bm = Bookmark()
+
+We would now like to only add validated values to the class. This can be done
+by first validating and then setting the value on the object. The first step
+is to define some data:
+
+.. doctest::
+
+   >>> title = u('Zope 3 Website')
+   >>> url = b('http://dev.zope.org/Zope3')
+
+Now we, get the fields from the interface:
+
+.. doctest::
+
+   >>> title_field = IBookmark.get('title')
+   >>> url_field = IBookmark.get('url')
+
+Next we have to bind these fields to the context, so that instance-specific
+information can be used for validation:
+
+.. doctest::
+
+   >>> title_bound = title_field.bind(bm)
+   >>> url_bound = url_field.bind(bm)
+
+Now that the fields are bound, we can finally validate the data:
+
+.. doctest::
+
+   >>> title_bound.validate(title)
+   >>> url_bound.validate(url)
+
+If the validation is successful, ``None`` is returned. If a validation error
+occurs a ``ValidationError`` will be raised; for example:
+
+.. doctest::
+
+   >>> url_bound.validate(u('http://zope.org/foo'))
+   Traceback (most recent call last):
+   ...
+   WrongType: (u'http://zope.org/foo', <type 'str'>, 'url')
+
+   >>> url_bound.validate(b('foo.bar'))
+   Traceback (most recent call last):
+   ...
+   InvalidURI: foo.bar
+
+Now that the data has been successfully validated, we can set it on the
+object:
+
+.. doctest::
+
+   >>> title_bound.set(bm, title)
+   >>> url_bound.set(bm, url)
+
+That's it. You still might think this is a lot of work to validate and set a
+value for an object. Note, however, that it is very easy to write helper
+functions that automate these tasks. If correctly designed, you will never
+have to worry explicitly about validation again, since the system takes care
+of it automatically.
+
+
+What is a schema, how does it compare to an interface?
+------------------------------------------------------
+
+A schema is an extended interface which defines fields.  You can validate that
+the attributes of an object conform to their fields defined on the schema.
+With plain interfaces you can only validate that methods conform to their
+interface specification.
+
+So interfaces and schemas refer to different aspects of an object
+(respectively its code and state).
+
+A schema starts out like an interface but defines certain fields to
+which an object's attributes must conform.  Let's look at a stripped
+down example from the programmer's tutorial:
+
+.. doctest::
+
+   >>> import re
+
+   >>> class IContact(zope.interface.Interface):
+   ...     """Provides access to basic contact information."""
+   ...
+   ...     first = zope.schema.TextLine(title=u("First name"))
+   ...
+   ...     last = zope.schema.TextLine(title=u("Last name"))
+   ...
+   ...     email = zope.schema.TextLine(title=u("Electronic mail address"))
+   ...
+   ...     address = zope.schema.Text(title=u("Postal address"))
+   ...
+   ...     postalCode = zope.schema.TextLine(
+   ...         title=u("Postal code"),
+   ...         constraint=re.compile("\d{5,5}(-\d{4,4})?$").match)
+
+``TextLine`` is a field and expresses that an attribute is a single line
+of Unicode text.  ``Text`` expresses an arbitrary Unicode ("text")
+object.  The most interesting part is the last attribute
+specification.  It constrains the ``postalCode`` attribute to only have
+values that are US postal codes.
+
+Now we want a class that adheres to the ``IContact`` schema:
+
+.. doctest::
+
+   >>> class Contact(object):
+   ...     zope.interface.implements(IContact)
+   ...
+   ...     def __init__(self, first, last, email, address, pc):
+   ...         self.first = first
+   ...         self.last = last
+   ...         self.email = email
+   ...         self.address = address
+   ...         self.postalCode = pc
+
+Now you can see if an instance of ``Contact`` actually implements the
+schema:
+
+.. doctest::
+
+   >>> someone = Contact(u('Tim'), u('Roberts'), u('tim at roberts'), u(''),
+   ...                   u('12032-3492'))
+
+   >>> for field in zope.schema.getFields(IContact).values():
+   ...     bound = field.bind(someone)
+   ...     bound.validate(bound.get(someone))
+
+
+Data Modeling Concepts
+-----------------------
+
+The ``zope.schema`` package provides a core set of field types,
+including single- and multi-line text fields, binary data fields,
+integers, floating-point numbers, and date/time values.
+
+Selection issues; field type can specify:
+
+- "Raw" data value
+
+  Simple values not constrained by a selection list.
+
+- Value from enumeration (options provided by schema)
+
+  This models a single selection from a list of possible values
+  specified by the schema.  The selection list is expected to be the
+  same for all values of the type.  Changes to the list are driven by
+  schema evolution.
+
+  This is done by mixing-in the ``IEnumerated`` interface into the field
+  type, and the Enumerated mix-in for the implementation (or emulating
+  it in a concrete class).
+
+- Value from selection list (options provided by an object)
+
+  This models a single selection from a list of possible values
+  specified by a source outside the schema.  The selection list
+  depends entirely on the source of the list, and may vary over time
+  and from object to object.  Changes to the list are not related to
+  the schema, but changing how the list is determined is based on
+  schema evolution.
+
+  There is not currently a spelling of this, but it could be
+  facilitated using alternate mix-ins similar to IEnumerated and
+  Enumerated.
+
+- Whether or not the field is read-only
+
+  If a field value is read-only, it cannot be changed once the object is
+  created.
+
+- Whether or not the field is required
+
+  If a field is designated as required, assigned field values must always
+  be non-missing. See the next section for a description of missing values.
+
+- A value designated as ``missing``
+
+  Missing values, when assigned to an object, indicate that there is 'no
+  data' for that field. Missing values are analogous to null values in
+  relational databases. For example, a boolean value can be True, False, or
+  missing, in which case its value is unknown.
+
+  While Python's None is the most likely value to signify 'missing', some
+  fields may use different values. For example, it is common for text fields
+  to use the empty string ('') to signify that a value is missing. Numeric
+  fields may use 0 or -1 instead of None as their missing value.
+
+  A field that is 'required' signifies that missing values are invalid and
+  should not be assigned.
+
+- A default value
+
+  Default field values are assigned to objects when they are first created. A
+  default factory can be specified to dynamically compute default values.
+
+
+Fields and Widgets
+------------------
+
+Widgets are components that display field values and, in the case of
+writable fields, allow the user to edit those values.
+
+Widgets:
+
+- Display current field values, either in a read-only format, or in a
+  format that lets the user change the field value.
+
+- Update their corresponding field values based on values provided by users.
+
+- Manage the relationships between their representation of a field value
+  and the object's field value. For example, a widget responsible for
+  editing a number will likely represent that number internally as a string.
+  For this reason, widgets must be able to convert between the two value
+  formats. In the case of the number-editing widget, string values typed
+  by the user need to be converted to numbers such as int or float.
+
+- Support the ability to assign a missing value to a field. For example,
+  a widget may present a ``None`` option for selection that, when selected,
+  indicates that the object should be updated with the field's ``missing``
+  value.
+
+
+
+References
+----------
+
+- Use case list, http://dev.zope.org/Zope3/Zope3SchemasUseCases
+
+- Documented interfaces, zope/schema/interfaces.py
+
+- Jim Fulton's Programmers Tutorial; in CVS:
+  Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter2

Copied: zope.schema/branches/tseaver-test_cleanup/docs/sources.rst (from rev 125215, zope.schema/branches/tseaver-test_cleanup/src/zope/schema/sources.txt)
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/sources.rst	                        (rev 0)
+++ zope.schema/branches/tseaver-test_cleanup/docs/sources.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -0,0 +1,107 @@
+=======
+Sources
+=======
+
+Concepts
+--------
+
+Sources are designed with three concepts:
+
+- The source itself - an iterable
+
+  This can return any kind of object it wants. It doesn't have to care
+  for browser representation, encoding, ...
+
+- A way to map a value from the iterable to something that can be used
+  for form *values* - this is called a token. A token is commonly a
+  (unique) 7bit representation of the value.
+
+- A way to map a value to something that can be displayed to the user -
+  this is called a title
+
+The last two elements are dispatched using a so called `term`. The
+ITitledTokenizedTerm interface contains a triple of (value, token, title).
+
+Additionally there are some lookup functions to perform the mapping
+between values and terms and tokens and terms.
+
+Sources that require context use a special factory: a context source
+binder that is called with the context and instanciates the source when
+it is actually used.
+
+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.
+
+.. doctest::
+
+   >>> from zope import interface
+   >>> from zope.schema.interfaces import ISource, IContextSourceBinder
+   >>> @interface.implementer(ISource)
+   ... class MySource(object):
+   ...     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.
+
+.. doctest::
+
+   >>> _my_binder_called = []
+   >>> def my_binder(context):
+   ...     _my_binder_called.append(context)   
+   ...     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())
+   >>> len(_my_binder_called)
+   1
+   >>> bound.vocabulary
+   <...MySource...>
+   >>> bound.vocabulary.divisor
+   3
+
+When using IContextSourceBinder together with default value, it's
+impossible to validate it on field initialization. Let's check if
+initalization doesn't fail in that case.
+
+.. doctest::
+
+   >>> choice = Choice(__name__='number', source=my_binder, default=2)
+
+   >>> del _my_binder_called[:]
+   >>> bound = choice.bind(Context())
+   >>> len(_my_binder_called)
+   1
+
+   >>> bound.validate(bound.default)
+   >>> bound.validate(3)
+   Traceback (most recent call last):
+   ...
+   ConstraintNotSatisfied: 3
+
+It's developer's responsibility to provide a default value that fits the
+constraints when using context-based sources.

Copied: zope.schema/branches/tseaver-test_cleanup/docs/validation.rst (from rev 125215, zope.schema/branches/tseaver-test_cleanup/src/zope/schema/validation.txt)
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/docs/validation.rst	                        (rev 0)
+++ zope.schema/branches/tseaver-test_cleanup/docs/validation.rst	2012-04-20 19:20:50 UTC (rev 125216)
@@ -0,0 +1,217 @@
+=================
+Schema Validation
+=================
+
+There are two helper methods to verify schemas and interfaces:
+
+getValidationErrors
+    first validates via the zope.schema field validators. If that succeeds the
+    invariants are checked.
+getSchemaValidationErrors
+    *only* validateds via the zope.schema field validators. The invariants are
+    *not* checked.
+
+
+Create an interface to validate against:
+
+.. doctest::
+
+   >>> import zope.interface
+   >>> import zope.schema
+   >>> _a_greater_b_called = []
+   >>> class ITwoInts(zope.interface.Interface):
+   ...     a = zope.schema.Int(max=10)
+   ...     b = zope.schema.Int(min=5)
+   ...
+   ...     @zope.interface.invariant
+   ...     def a_greater_b(obj):
+   ...         _a_greater_b_called.append(obj)
+   ...         if obj.a <= obj.b:
+   ...             raise zope.interface.Invalid("%s<=%s" % (obj.a, obj.b))
+   ...     
+
+Create a silly model:
+
+.. doctest::
+
+   >>> class TwoInts(object):
+   ...     pass
+
+Create an instance of TwoInts but do not set attributes. We get two errors:
+
+.. doctest::
+
+   >>> ti = TwoInts()
+   >>> r = zope.schema.getValidationErrors(ITwoInts, ti)
+   >>> r.sort()
+   >>> len(r)
+   2
+   >>> r[0][0]
+   'a'
+   >>> r[0][1].__class__.__name__
+   'SchemaNotFullyImplemented'
+   >>> r[0][1].args[0].args
+   ("'TwoInts' object has no attribute 'a'",)
+   >>> r[1][0]
+   'b'
+   >>> r[1][1].__class__.__name__
+   'SchemaNotFullyImplemented'
+   >>> r[1][1].args[0].args
+   ("'TwoInts' object has no attribute 'b'",)
+
+The `getSchemaValidationErrors` function returns the same result:
+
+.. doctest::
+
+   >>> r = zope.schema.getSchemaValidationErrors(ITwoInts, ti)
+   >>> r.sort()
+   >>> len(r)
+   2
+   >>> r[0][0]
+   'a'
+   >>> r[0][1].__class__.__name__
+   'SchemaNotFullyImplemented'
+   >>> r[0][1].args[0].args
+   ("'TwoInts' object has no attribute 'a'",)
+   >>> r[1][0]
+   'b'
+   >>> r[1][1].__class__.__name__
+   'SchemaNotFullyImplemented'
+   >>> r[1][1].args[0].args
+   ("'TwoInts' object has no attribute 'b'",)
+ 
+Note that see no error from the invariant because the invariants are not
+vaildated if there are other schema errors.
+
+When we set a valid value for `a` we still get the same error for `b`:
+
+.. doctest::
+
+   >>> ti.a = 11
+   >>> errors = zope.schema.getValidationErrors(ITwoInts, ti)
+   >>> errors.sort()
+   >>> len(errors)
+   2
+   >>> errors[0][0]
+   'a'
+   >>> errors[0][1].doc()
+   u'Value is too big'
+   >>> errors[0][1].__class__.__name__
+   'TooBig'
+   >>> errors[0][1].args
+   (11, 10)
+   >>> errors[1][0]
+   'b'
+   >>> errors[1][1].__class__.__name__
+   'SchemaNotFullyImplemented'
+   >>> errors[1][1].args[0].args
+   ("'TwoInts' object has no attribute 'b'",)
+
+
+After setting a valid value for `a` there is only the error for the missing `b`
+left:
+
+.. doctest::
+
+   >>> ti.a = 8
+   >>> r = zope.schema.getValidationErrors(ITwoInts, ti)
+   >>> r
+   [('b', SchemaNotFullyImplemented(...AttributeError...))]
+   >>> r[0][1].args[0].args
+   ("'TwoInts' object has no attribute 'b'",)
+
+
+After setting valid value for `b` the schema is valid so the invariants are
+checked. As `b>a` the invariant fails:
+
+.. doctest::
+
+   >>> ti.b = 10
+   >>> errors = zope.schema.getValidationErrors(ITwoInts, ti)
+   >>> len(errors)
+   1
+   >>> errors[0][0] is None
+   True
+   >>> errors[0][1].__class__.__name__
+   'Invalid'
+   >>> len(_a_greater_b_called)
+   1
+
+
+When using `getSchemaValidationErrors` we do not get an error any more:
+
+.. doctest::
+
+   >>> zope.schema.getSchemaValidationErrors(ITwoInts, ti)
+   []
+
+
+Set `b=5` so everything is fine:
+
+.. doctest::
+
+   >>> ti.b = 5
+   >>> del _a_greater_b_called[:]
+   >>> zope.schema.getValidationErrors(ITwoInts, ti)
+   []
+   >>> len(_a_greater_b_called)
+   1
+
+
+Compare ValidationError
+-----------------------
+
+There was an issue with compare validation error with somthing else then an
+exceptions. Let's test if we can compare ValidationErrors with different things
+
+.. doctest::
+
+   >>> from zope.schema._bootstrapinterfaces import ValidationError
+   >>> v1 = ValidationError('one')
+   >>> v2 = ValidationError('one')
+   >>> v3 = ValidationError('another one')
+
+A ValidationError with the same arguments compares:
+
+.. doctest::
+
+   >>> v1 == v2
+   True
+
+but not with an error with different arguments:
+
+.. doctest::
+
+   >>> v1 == v3
+   False
+
+We can also compare validation erros with other things then errors. This 
+was running into an AttributeError in previous versions of zope.schema. e.g.
+AttributeError: 'NoneType' object has no attribute 'args'
+
+.. doctest::
+
+   >>> v1 == None
+   False
+   >>> v1 == object()
+   False
+   >>> v1 == False
+   False
+   >>> v1 == True
+   False
+   >>> v1 == 0
+   False
+   >>> v1 == 1
+   False
+   >>> v1 == int
+   False
+
+If we compare a ValidationError with another validation error based class,
+we will get the following result:
+
+.. doctest::
+
+   >>> from zope.schema._bootstrapinterfaces import RequiredMissing
+   >>> r1 = RequiredMissing('one')
+   >>> v1 == r1
+   True

Modified: zope.schema/branches/tseaver-test_cleanup/setup.py
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/setup.py	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/setup.py	2012-04-20 19:20:50 UTC (rev 125216)
@@ -79,15 +79,7 @@
       description='zope.interface extension for defining data schemas',
       author='Zope Foundation and Contributors',
       author_email='zope-dev at zope.org',
-      long_description=(read('src', 'zope', 'schema', 'README.txt')
-                        + '\n\n' +
-                        read('src', 'zope', 'schema', 'fields.txt')
-                        + '\n\n' +
-                        read('src', 'zope', 'schema', 'sources.txt')
-                        + '\n\n' +
-                        read('src', 'zope', 'schema', 'validation.txt')
-                        + '\n\n' +
-                        read('CHANGES.txt')),
+      long_description=(read('README.txt') + '\n\n' + read('CHANGES.txt')),
       packages=find_packages('src'),
       package_dir = {'': 'src'},
       namespace_packages=['zope',],

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/README.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/README.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/README.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,276 +0,0 @@
-==============
-Zope 3 Schemas
-==============
-
-Introduction
-------------
-
-*This package is intended to be independently reusable in any Python
-project. It is maintained by the* `Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
-
-Schemas extend the notion of interfaces to detailed descriptions of Attributes
-(but not methods). Every schema is an interface and specifies the public
-fields of an object. A *field* roughly corresponds to an attribute of a
-python object. But a Field provides space for at least a title and a
-description. It can also constrain its value and provide a validation method.
-Besides you can optionally specify characteristics such as its value being
-read-only or not required.
-
-Zope 3 schemas were born when Jim Fulton and Martijn Faassen thought
-about Formulator for Zope 3 and ``PropertySets`` while at the `Zope 3
-sprint`_ at the Zope BBQ in Berlin. They realized that if you strip
-all view logic from forms then you have something similar to interfaces. And
-thus schemas were born.
-
-.. _Zope 3 sprint: http://dev.zope.org/Zope3/ZopeBBQ2002Sprint
-
-.. contents::
-
-Simple Usage
-------------
-
-Let's have a look at a simple example. First we write an interface as usual,
-but instead of describing the attributes of the interface with ``Attribute``
-instances, we now use schema fields:
-
-  >>> import zope.interface
-  >>> import zope.schema
-  >>> from zope.schema._compat import u, b
-
-  >>> class IBookmark(zope.interface.Interface):
-  ...     title = zope.schema.TextLine(
-  ...         title=u('Title'),
-  ...         description=u('The title of the bookmark'),
-  ...         required=True)
-  ...
-  ...     url = zope.schema.URI(
-  ...         title=u('Bookmark URL'),
-  ...         description=u('URL of the Bookmark'),
-  ...         required=True)
-  ...
-
-Now we create a class that implements this interface and create an instance of
-it:
-
-  >>> @zope.interface.implementer(IBookmark)
-  ... class Bookmark(object):
-  ...
-  ...     title = None
-  ...     url = None
-
-  >>> bm = Bookmark()
-
-We would now like to only add validated values to the class. This can be done
-by first validating and then setting the value on the object. The first step
-is to define some data:
-
-  >>> title = u('Zope 3 Website')
-  >>> url = b('http://dev.zope.org/Zope3')
-
-Now we, get the fields from the interface:
-
-  >>> title_field = IBookmark.get('title')
-  >>> url_field = IBookmark.get('url')
-
-Next we have to bind these fields to the context, so that instance-specific
-information can be used for validation:
-
-  >>> title_bound = title_field.bind(bm)
-  >>> url_bound = url_field.bind(bm)
-
-Now that the fields are bound, we can finally validate the data:
-
-  >>> title_bound.validate(title)
-  >>> url_bound.validate(url)
-
-If the validation is successful, ``None`` is returned. If a validation error
-occurs a ``ValidationError`` will be raised; for example:
-
-  >>> url_bound.validate(u('http://zope.org/foo'))
-  Traceback (most recent call last):
-  ...
-  WrongType: (u'http://zope.org/foo', <type 'str'>, 'url')
-
-  >>> url_bound.validate(b('foo.bar'))
-  Traceback (most recent call last):
-  ...
-  InvalidURI: foo.bar
-
-Now that the data has been successfully validated, we can set it on the
-object:
-
-  >>> title_bound.set(bm, title)
-  >>> url_bound.set(bm, url)
-
-That's it. You still might think this is a lot of work to validate and set a
-value for an object. Note, however, that it is very easy to write helper
-functions that automate these tasks. If correctly designed, you will never
-have to worry explicitly about validation again, since the system takes care
-of it automatically.
-
-
-What is a schema, how does it compare to an interface?
-------------------------------------------------------
-
-A schema is an extended interface which defines fields.  You can validate that
-the attributes of an object conform to their fields defined on the schema.
-With plain interfaces you can only validate that methods conform to their
-interface specification.
-
-So interfaces and schemas refer to different aspects of an object
-(respectively its code and state).
-
-A schema starts out like an interface but defines certain fields to
-which an object's attributes must conform.  Let's look at a stripped
-down example from the programmer's tutorial:
-
-    >>> import re
-
-    >>> class IContact(zope.interface.Interface):
-    ...     """Provides access to basic contact information."""
-    ...
-    ...     first = zope.schema.TextLine(title=u("First name"))
-    ...
-    ...     last = zope.schema.TextLine(title=u("Last name"))
-    ...
-    ...     email = zope.schema.TextLine(title=u("Electronic mail address"))
-    ...
-    ...     address = zope.schema.Text(title=u("Postal address"))
-    ...
-    ...     postalCode = zope.schema.TextLine(
-    ...         title=u("Postal code"),
-    ...         constraint=re.compile("\d{5,5}(-\d{4,4})?$").match)
-
-``TextLine`` is a field and expresses that an attribute is a single line
-of Unicode text.  ``Text`` expresses an arbitrary Unicode ("text")
-object.  The most interesting part is the last attribute
-specification.  It constrains the ``postalCode`` attribute to only have
-values that are US postal codes.
-
-Now we want a class that adheres to the ``IContact`` schema:
-
-    >>> class Contact(object):
-    ...     zope.interface.implements(IContact)
-    ...
-    ...     def __init__(self, first, last, email, address, pc):
-    ...         self.first = first
-    ...         self.last = last
-    ...         self.email = email
-    ...         self.address = address
-    ...         self.postalCode = pc
-
-Now you can see if an instance of ``Contact`` actually implements the
-schema:
-
-    >>> someone = Contact(u('Tim'), u('Roberts'), u('tim at roberts'), u(''),
-    ...                   u('12032-3492'))
-
-    >>> for field in zope.schema.getFields(IContact).values():
-    ...     bound = field.bind(someone)
-    ...     bound.validate(bound.get(someone))
-
-
-Data Modeling Concepts
------------------------
-
-The ``zope.schema`` package provides a core set of field types,
-including single- and multi-line text fields, binary data fields,
-integers, floating-point numbers, and date/time values.
-
-Selection issues; field type can specify:
-
-- "Raw" data value
-
-  Simple values not constrained by a selection list.
-
-- Value from enumeration (options provided by schema)
-
-  This models a single selection from a list of possible values
-  specified by the schema.  The selection list is expected to be the
-  same for all values of the type.  Changes to the list are driven by
-  schema evolution.
-
-  This is done by mixing-in the ``IEnumerated`` interface into the field
-  type, and the Enumerated mix-in for the implementation (or emulating
-  it in a concrete class).
-
-- Value from selection list (options provided by an object)
-
-  This models a single selection from a list of possible values
-  specified by a source outside the schema.  The selection list
-  depends entirely on the source of the list, and may vary over time
-  and from object to object.  Changes to the list are not related to
-  the schema, but changing how the list is determined is based on
-  schema evolution.
-
-  There is not currently a spelling of this, but it could be
-  facilitated using alternate mix-ins similar to IEnumerated and
-  Enumerated.
-
-- Whether or not the field is read-only
-
-  If a field value is read-only, it cannot be changed once the object is
-  created.
-
-- Whether or not the field is required
-
-  If a field is designated as required, assigned field values must always
-  be non-missing. See the next section for a description of missing values.
-
-- A value designated as ``missing``
-
-  Missing values, when assigned to an object, indicate that there is 'no
-  data' for that field. Missing values are analogous to null values in
-  relational databases. For example, a boolean value can be True, False, or
-  missing, in which case its value is unknown.
-
-  While Python's None is the most likely value to signify 'missing', some
-  fields may use different values. For example, it is common for text fields
-  to use the empty string ('') to signify that a value is missing. Numeric
-  fields may use 0 or -1 instead of None as their missing value.
-
-  A field that is 'required' signifies that missing values are invalid and
-  should not be assigned.
-
-- A default value
-
-  Default field values are assigned to objects when they are first created. A
-  default factory can be specified to dynamically compute default values.
-
-
-Fields and Widgets
-------------------
-
-Widgets are components that display field values and, in the case of
-writable fields, allow the user to edit those values.
-
-Widgets:
-
-- Display current field values, either in a read-only format, or in a
-  format that lets the user change the field value.
-
-- Update their corresponding field values based on values provided by users.
-
-- Manage the relationships between their representation of a field value
-  and the object's field value. For example, a widget responsible for
-  editing a number will likely represent that number internally as a string.
-  For this reason, widgets must be able to convert between the two value
-  formats. In the case of the number-editing widget, string values typed
-  by the user need to be converted to numbers such as int or float.
-
-- Support the ability to assign a missing value to a field. For example,
-  a widget may present a ``None`` option for selection that, when selected,
-  indicates that the object should be updated with the field's ``missing``
-  value.
-
-
-
-References
-----------
-
-- Use case list, http://dev.zope.org/Zope3/Zope3SchemasUseCases
-
-- Documented interfaces, zope/schema/interfaces.py
-
-- Jim Fulton's Programmers Tutorial; in CVS:
-  Docs/ZopeComponentArchitecture/PythonProgrammerTutorial/Chapter2

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/fields.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/fields.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/fields.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,163 +0,0 @@
-======
-Fields
-======
-
-This document highlights unusual and subtle aspects of various fields and
-field classes, and is not intended to be a general introduction to schema
-fields.  Please see README.txt for a more general introduction.
-
-While many field types, such as Int, TextLine, Text, and Bool are relatively
-straightforward, a few have some subtlety.  We will explore the general
-class of collections and discuss how to create a custom creation field; discuss
-Choice fields, vocabularies, and their use with collections; and close with a
-look at the standard zope.app approach to using these fields to find views
-("widgets").
-
-Collections
------------
-
-Normal fields typically describe the API of the attribute -- does it behave as a
-Python Int, or a Float, or a Bool -- and various constraints to the model, such
-as a maximum or minimum value.  Collection fields have additional requirements
-because they contain other types, which may also be described and constrained.
-
-For instance, imagine a list that contains non-negative floats and enforces
-uniqueness. In a schema, this might be written as follows:
-
-  >>> from zope.interface import Interface
-  >>> from zope.schema import List, Float
-  >>> from zope.schema._compat import u
-  >>> class IInventoryItem(Interface):
-  ...     pricePoints = List(
-  ...         title=u("Price Points"),
-  ...         unique=True,
-  ...         value_type=Float(title=u("Price"), min=0.0)
-  ...     )
-
-This indicates several things.
-
-- pricePoints is an attribute of objects that implement IInventoryItem.
-- The contents of pricePoints can be accessed and manipulated via a Python list
-  API.
-- Each member of pricePoints must be a non-negative float.
-- Members cannot be duplicated within pricePoints: each must be must be unique.
-- The attribute and its contents have descriptive titles.  Typically these
-  would be message ids.
-
-This declaration creates a field that implements a number of interfaces, among
-them these:
-
-  >>> from zope.schema.interfaces import IList, ISequence, ICollection
-  >>> IList.providedBy(IInventoryItem['pricePoints'])
-  True
-  >>> ISequence.providedBy(IInventoryItem['pricePoints'])
-  True
-  >>> ICollection.providedBy(IInventoryItem['pricePoints'])
-  True
-
-Creating a custom collection field
-----------------------------------
-
-Ideally, custom collection fields have interfaces that inherit appropriately
-from either zope.schema.interfaces.ISequence or
-zope.schema.interfaces.IUnorderedCollection.  Most collection fields should be
-able to subclass zope.schema._field.AbstractCollection to get the necessary
-behavior.  Notice the behavior of the Set field in zope.schema._field: this
-would also be necessary to implement a Bag.
-
-Choices and Vocabularies
-------------------------
-
-Choice fields are the schema way of spelling enumerated fields and more.  By
-providing a dynamically generated vocabulary, the choices available to a
-choice field can be contextually calculated.  
-
-Simple choices do not have to explicitly use vocabularies:
-
-  >>> from zope.schema import Choice
-  >>> f = Choice((640, 1028, 1600))
-  >>> f.validate(640)
-  >>> f.validate(960)
-  Traceback (most recent call last):
-  ...
-  ConstraintNotSatisfied: 960
-  >>> f.validate('bing')
-  Traceback (most recent call last):
-  ...
-  ConstraintNotSatisfied: bing
-
-More complex choices will want to use registered vocabularies.  Vocabularies
-have a simple interface, as defined in
-zope.schema.interfaces.IBaseVocabulary.  A vocabulary must minimally be able
-to determine whether it contains a value, to create a term object for a value,
-and to return a query interface (or None) to find items in itself.  Term
-objects are an abstraction that wraps a vocabulary value.  
-
-The Zope application server typically needs a fuller interface that provides
-"tokens" on its terms: ASCII values that have a one-to-one relationship to the
-values when the vocabulary is asked to "getTermByToken".  If a vocabulary is
-small, it can also support the IIterableVocabulary interface.
-
-If a vocabulary has been registered, then the choice merely needs to pass the
-vocabulary identifier to the "vocabulary" argument of the choice during
-instantiation.
-
-A start to a vocabulary implementation that may do all you need for many simple
-tasks may be found in zope.schema.vocabulary.SimpleVocabulary.  Because
-registered vocabularies are simply callables passed a context, many
-registered vocabularies can simply be functions that rely on SimpleVocabulary:
-
-  >>> from zope.schema.vocabulary import SimpleVocabulary
-  >>> def myDynamicVocabulary(context):
-  ...     v = dynamic_context_calculation_that_returns_an_iterable(context)
-  ...     return SimpleVocabulary.fromValues(v)
-  ... 
-
-The vocabulary interface is simple enough that writing a custom vocabulary is
-not too difficult itself.
-
-See zope.schema.vocabulary.TreeVocabulary for another
-IBaseVocabulary supporting vocabulary that provides a nested, tree-like 
-structure.
-
-Choices and Collections
------------------------
-
-Choices are a field type and can be used as a value_type for collections. Just
-as a collection of an "Int" value_type constrains members to integers, so a
-choice-based value type constrains members to choices within the Choice's
-vocabulary.  Typically in the Zope application server widgets are found not
-only for the collection and the choice field but also for the vocabulary on
-which the choice is based.
-
-Using Choice and Collection Fields within a Widget Framework
-------------------------------------------------------------
-
-While fields support several use cases, including code documentation and data
-description and even casting, a significant use case influencing their design is
-to support form generation -- generating widgets for a field.  Choice and
-collection fields are expected to be used within widget frameworks.  The
-zope.app approach typically (but configurably) uses multiple dispatches to 
-find widgets on the basis of various aspects of the fields.
-
-Widgets for all fields are found by looking up a browser view of the field
-providing an input or display widget view.  Typically there is only a single
-"widget" registered for Choice fields.  When it is looked up, it performs
-another dispatch -- another lookup -- for a widget registered for both the field
-and the vocabulary.  This widget typically has enough information to render
-without a third dispatch.
-
-Collection fields may fire several dispatches.  The first is the usual lookup
-by field.  A single "widget" should be registered for ICollection, which does
-a second lookup by field and value_type constraint, if any, or, theoretically,
-if value_type is None, renders some absolutely generic collection widget that
-allows input of any value imaginable: a check-in of such a widget would be
-unexpected.  This second lookup may find a widget that knows how to render,
-and stop.  However, the value_type may be a choice, which will usually fire a
-third dispatch: a search for a browser widget for the collection field, the
-value_type field, and the vocabulary.  Further lookups may even be configured
-on the basis of uniqueness and other constraints.
-
-This level of indirection may be unnecessary for some applications, and can be
-disabled with simple ZCML changes within `zope.app`.
-

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/index.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/index.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/index.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,19 +0,0 @@
-Welcome to zope.schema's documentation!
-=======================================
-
-Contents:
-
-.. toctree::
-   :maxdepth: 2
-
-   README
-   fields
-   sources
-   validation
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/sources.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/sources.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/sources.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,101 +0,0 @@
-=======
-Sources
-=======
-
-Concepts
---------
-
-Sources are designed with three concepts:
-
-- The source itself - an iterable
-
-  This can return any kind of object it wants. It doesn't have to care
-  for browser representation, encoding, ...
-
-- A way to map a value from the iterable to something that can be used
-  for form *values* - this is called a token. A token is commonly a
-  (unique) 7bit representation of the value.
-
-- A way to map a value to something that can be displayed to the user -
-  this is called a title
-
-The last two elements are dispatched using a so called `term`. The
-ITitledTokenizedTerm interface contains a triple of (value, token, title).
-
-Additionally there are some lookup functions to perform the mapping
-between values and terms and tokens and terms.
-
-Sources that require context use a special factory: a context source
-binder that is called with the context and instanciates the source when
-it is actually used.
-
-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
-    >>> @interface.implementer(ISource)
-    ... class MySource(object):
-    ...     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.
-
-    >>> _my_binder_called = []
-    >>> def my_binder(context):
-    ...     _my_binder_called.append(context)   
-    ...     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())
-    >>> len(_my_binder_called)
-    1
-    >>> bound.vocabulary
-    <...MySource...>
-    >>> bound.vocabulary.divisor
-    3
-
-When using IContextSourceBinder together with default value, it's
-impossible to validate it on field initialization. Let's check if
-initalization doesn't fail in that case.
-
-    >>> choice = Choice(__name__='number', source=my_binder, default=2)
-
-    >>> del _my_binder_called[:]
-    >>> bound = choice.bind(Context())
-    >>> len(_my_binder_called)
-    1
-
-    >>> bound.validate(bound.default)
-    >>> bound.validate(3)
-    Traceback (most recent call last):
-    ...
-    ConstraintNotSatisfied: 3
-
-It's developer's responsibility to provide a default value that fits the
-constraints when using context-based sources.

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/tests/test_docs.py
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/tests/test_docs.py	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/tests/test_docs.py	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,38 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Tests for the schema package's documentation files
-"""
-import unittest
-
-def test_suite():
-    import doctest
-    import re
-
-    from zope.testing import renormalizing
-    import zope.schema.tests
-    checker = renormalizing.RENormalizing([
-        (re.compile(r"\[\(None, Invalid\('8<=10',\)\)\]"),
-                    r"[(None, <zope.interface.exceptions.Invalid instance at 0x...>)]",)
-      ])
-    checker = checker + zope.schema.tests.py3_checker
-    return unittest.TestSuite((
-        doctest.DocFileSuite('../sources.txt',
-                             optionflags=doctest.ELLIPSIS,
-                             checker=zope.schema.tests.py3_checker),
-        doctest.DocFileSuite('../fields.txt', checker=zope.schema.tests.py3_checker),
-        doctest.DocFileSuite('../README.txt', checker=zope.schema.tests.py3_checker),
-        doctest.DocFileSuite(
-            '../validation.txt', checker=checker,
-            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
-        ))

Deleted: zope.schema/branches/tseaver-test_cleanup/src/zope/schema/validation.txt
===================================================================
--- zope.schema/branches/tseaver-test_cleanup/src/zope/schema/validation.txt	2012-04-20 19:20:46 UTC (rev 125215)
+++ zope.schema/branches/tseaver-test_cleanup/src/zope/schema/validation.txt	2012-04-20 19:20:50 UTC (rev 125216)
@@ -1,169 +0,0 @@
-=================
-Schema Validation
-=================
-
-There are two helper methods to verify schemas and interfaces:
-
-getValidationErrors
-    first validates via the zope.schema field validators. If that succeeds the
-    invariants are checked.
-getSchemaValidationErrors
-    *only* validateds via the zope.schema field validators. The invariants are
-    *not* checked.
-
-
-Create an interface to validate against:
-
-  >>> import zope.interface
-  >>> import zope.schema
-  >>> _a_greater_b_called = []
-  >>> class ITwoInts(zope.interface.Interface):
-  ...     a = zope.schema.Int(max=10)
-  ...     b = zope.schema.Int(min=5)
-  ...
-  ...     @zope.interface.invariant
-  ...     def a_greater_b(obj):
-  ...         _a_greater_b_called.append(obj)
-  ...         if obj.a <= obj.b:
-  ...             raise zope.interface.Invalid("%s<=%s" % (obj.a, obj.b))
-  ...     
-
-Create a silly model:
-
-  >>> class TwoInts(object):
-  ...     pass
-
-Create an instance of TwoInts but do not set attributes. We get two errors:
-
-  >>> ti = TwoInts()
-  >>> r = zope.schema.getValidationErrors(ITwoInts, ti)
-  >>> r.sort()
-  >>> r
-  [('a', SchemaNotFullyImplemented(...AttributeError...)),
-   ('b', SchemaNotFullyImplemented(...AttributeError...))]
-  >>> r[0][1].args[0].args
-  ("'TwoInts' object has no attribute 'a'",)
-  >>> r[1][1].args[0].args
-  ("'TwoInts' object has no attribute 'b'",)
-
-The `getSchemaValidationErrors` function returns the same result:
-
-  >>> r = zope.schema.getSchemaValidationErrors(ITwoInts, ti)
-  >>> r.sort()
-  >>> r
-  [('a', SchemaNotFullyImplemented(...AttributeError...)),
-   ('b', SchemaNotFullyImplemented(...AttributeError...))]
-  >>> r[0][1].args[0].args
-  ("'TwoInts' object has no attribute 'a'",)
-  >>> r[1][1].args[0].args
-  ("'TwoInts' object has no attribute 'b'",)
- 
-Note that see no error from the invariant because the invariants are not
-vaildated if there are other schema errors.
-
-When we set a valid value for `a` we still get the same error for `b`:
-
-  >>> ti.a = 11
-  >>> errors = zope.schema.getValidationErrors(ITwoInts, ti)
-  >>> errors.sort()
-  >>> errors
-  [('a', TooBig(11, 10)),
-   ('b', SchemaNotFullyImplemented(...AttributeError...))]
-  >>> errors[1][1].args[0].args
-  ("'TwoInts' object has no attribute 'b'",)
-
-  >>> errors[0][1].doc()
-  u'Value is too big'
-
-
-After setting a valid value for `a` there is only the error for the missing `b`
-left:
-
-  >>> ti.a = 8
-  >>> r = zope.schema.getValidationErrors(ITwoInts, ti)
-  >>> r
-  [('b', SchemaNotFullyImplemented(...AttributeError...))]
-  >>> r[0][1].args[0].args
-  ("'TwoInts' object has no attribute 'b'",)
-
-
-After setting valid value for `b` the schema is valid so the invariants are
-checked. As `b>a` the invariant fails:
-
-  >>> ti.b = 10
-  >>> errors = zope.schema.getValidationErrors(ITwoInts, ti)
-  >>> len(_a_greater_b_called)
-  1
-  >>> errors
-  [(None, <zope.interface.exceptions.Invalid instance at 0x...>)]
-
-
-When using `getSchemaValidationErrors` we do not get an error any more:
-
-  >>> zope.schema.getSchemaValidationErrors(ITwoInts, ti)
-  []
-
-
-Set `b=5` so everything is fine:
-
-  >>> ti.b = 5
-  >>> del _a_greater_b_called[:]
-  >>> zope.schema.getValidationErrors(ITwoInts, ti)
-  []
-  >>> len(_a_greater_b_called)
-  1
-
-
-Compare ValidationError
------------------------
-
-There was an issue with compare validation error with somthing else then an
-exceptions. Let's test if we can compare ValidationErrors with different things
-
-  >>> from zope.schema._bootstrapinterfaces import ValidationError
-  >>> v1 = ValidationError('one')
-  >>> v2 = ValidationError('one')
-  >>> v3 = ValidationError('another one')
-
-A ValidationError with the same arguments compares:
-
-  >>> v1 == v2
-  True
-
-but not with an error with different arguments:
-
-  >>> v1 == v3
-  False
-
-We can also compare validation erros with other things then errors. This 
-was running into an AttributeError in previous versions of zope.schema. e.g.
-AttributeError: 'NoneType' object has no attribute 'args'
-
-  >>> v1 == None
-  False
-
-  >>> v1 == object()
-  False
-
-  >>> v1 == False
-  False
-
-  >>> v1 == True
-  False
-
-  >>> v1 == 0
-  False
-
-  >>> v1 == 1
-  False
-
-  >>> v1 == int
-  False
-
-If we compare a ValidationError with another validation error based class,
-we will get the following result:
-
-  >>> from zope.schema._bootstrapinterfaces import RequiredMissing
-  >>> r1 = RequiredMissing('one')
-  >>> v1 == r1
-  True



More information about the checkins mailing list