[Testbot] Plone 5.0 - Python 2.7 - Build # 3093 - Still failing! - 0 failure(s)

jenkins at plone.org jenkins at plone.org
Sat Aug 23 05:39:35 UTC 2014


-------------------------------------------------------------------------------
Plone 5.0 - Python 2.7 - Build # 3093 - Still Failing!
-------------------------------------------------------------------------------

http://jenkins.plone.org/job/plone-5.0-python-2.7/3093/


-------------------------------------------------------------------------------
CHANGES
-------------------------------------------------------------------------------

Repository: plone.dexterity
Branch: refs/heads/master
Date: 2014-08-23T01:16:40+02:00
Author: Gil Forcada (gforcada) <gforcada at gnome.org>
Commit: https://github.com/plone/plone.dexterity/commit/1290aceedb849f9a3dae4ef8c02a8a163c32142f

Whitespaces cleanup

Files changed:
M README.rst
M docs/INSTALL.txt
M docs/LICENSE.txt
M docs/WebDAV.txt
M plone/dexterity/CONVENTIONS.txt
M plone/dexterity/behavior.py
M plone/dexterity/browser/add.py
M plone/dexterity/browser/configure.zcml
M plone/dexterity/browser/containercontentcore.pt
M plone/dexterity/browser/edit.py
M plone/dexterity/browser/fti.pt
M plone/dexterity/browser/item.pt
M plone/dexterity/browser/itemcontentcore.pt
M plone/dexterity/browser/traversal.py
M plone/dexterity/configure.zcml
M plone/dexterity/factory.py
M plone/dexterity/filerepresentation.py
M plone/dexterity/fti.py
M plone/dexterity/interfaces.py
M plone/dexterity/meta.zcml
M plone/dexterity/schema.py
M plone/dexterity/tests/schemata.py
M plone/dexterity/tests/test_content_integration.py
M plone/dexterity/tests/test_primary.py
M plone/dexterity/tests/test_security.py

diff --git a/README.rst b/README.rst
index 929980b..0204ef7 100644
--- a/README.rst
+++ b/README.rst
@@ -14,7 +14,7 @@ Dexterity wants to make some things really easy. These are:
 
 - Create a "real" content type entirely through-the-web without having to
   know programming.
-  
+
 - As a business user, create a schema using visual or through-the-web tools,
   and augment it with adapters, event handlers, and other Python code
   written on the filesystem by a Python programmer.
@@ -27,14 +27,14 @@ Dexterity wants to make some things really easy. These are:
   declarative fashion. Behaviours can be things like title-to-id naming,
   support for locking or versioning, or sets of standard metadata with
   associated UI elements.
- 
+
 - Easily package up and distribute content types defined through-the-web,
   on the filesystem, or using a combination of the two.
 
 Philosophy
 ----------
 
-Dexterity is designed with a specific philosophy in mind. This can be 
+Dexterity is designed with a specific philosophy in mind. This can be
 summarised as follows:
 
 Reuse over reinvention
@@ -42,15 +42,15 @@ Reuse over reinvention
    As far as possible, Dexterity should reuse components and technologies
    that already exist. More importantly, however, Dexterity should reuse
    *concepts* that exist elsewhere. It should be easy to learn Dexterity
-   by analogy, and to work with Dexterity types using familiar APIs and 
+   by analogy, and to work with Dexterity types using familiar APIs and
    techniques.
 
 Small over big
 
    Mega-frameworks be damned. Dexterity consists of a number of specialised
    packages, each of which is independently tested and reusable. Furthermore,
-   packages should have as few dependencies as possible, and should declare 
-   their dependencies explicitly. This helps keep the design clean and the 
+   packages should have as few dependencies as possible, and should declare
+   their dependencies explicitly. This helps keep the design clean and the
    code manageable.
 
 Natural interaction over excessive generality
@@ -75,15 +75,15 @@ Zope 3 over Zope 2
    Although Dexterity does not pretend to work with non-CMF systems, as
    many components as possible should work with plain Zope 3, and even where
    there are dependencies on Zope 2, CMF or Plone, they should - as far as
-   is practical - follow Zope 3 techniques and best practices. Many 
+   is practical - follow Zope 3 techniques and best practices. Many
    operations (e.g. managing objects in a folder, creating new objects
    or manipulating objects through a defined schema) are better designed in
-   Zope 3 than they were in Zope 2. 
+   Zope 3 than they were in Zope 2.
 
 Zope concepts over new paradigms
 
    We want Dexterity to be "Zope-ish" (and really, "Zope 3-ish"). Zope is a
-   mature, well-designed (well, mostly) and battle tested platform. We do 
+   mature, well-designed (well, mostly) and battle tested platform. We do
    not want to invent brand new paradigms and techniques if we can help it.
 
 Automated testing over wishful thinking
@@ -102,17 +102,17 @@ The model
 
    The Dexterity "model" describes a type's schemata (most types will have
    only one) and metadata associated with those schemata. A schema is just
-   a series of fields that can be used to render add/edit forms and 
+   a series of fields that can be used to render add/edit forms and
    introspect an object of the given type. The metadata storage is extensible
    via the component architecture. Typical forms of metadata include UI
    hints such as specifying the type of widget to use when rendering a
    particular field, and per-field security settings.
-   
-   The model is typically described in XML, though at runtime it is an 
-   instance of an object providing the IModel interface from 
+
+   The model is typically described in XML, though at runtime it is an
+   instance of an object providing the IModel interface from
    plone.supermodel. Schemata in the model are interfaces with zope.schema
    fields.
-   
+
    The model can exist purely as data in the ZODB if a type is created
    through-the-web. Alternatively, it can be loaded from a file. The XML
    representation is intended to be human-readable and self-documenting.
@@ -125,7 +125,7 @@ The schema
    simply an Interface with zope.schema fields. The schema can be specified
    in Python code (in which case it is simply referenced by name), or it
    can be loaded from an XML model.
-   
+
    The unnamed schema is also known as the IContentType schema, in that the
    schema interface will provide the Zope 3 IContentType interface. This
    means that if you call queryContentType() on a Dexterity content object,
@@ -139,14 +139,14 @@ The class
    Of course, all content objects are instances of a particular class.
    It is easy to provide your own class, and Dexterity has convenient
    base classes for you to use. However, many types will not need a class
-   at all. Instead, they will use the standard Dexterity "Item" and 
+   at all. Instead, they will use the standard Dexterity "Item" and
    "Container" classes.
-   
+
    Dexterity's content factory will initialise an object of one of these
    classes with the fields in the type's content schema, and will ensure
    that objects provide the relevant interfaces, including the schema
    interface itself.
-   
+
    The preferred way to add behaviour and logic to Dexterity content objects
    is via adapters. In this case, you will probably want a filesystem
    version of the schema interface (this can still be loaded from XML if you
@@ -158,11 +158,11 @@ The factory
    Dexterity content is constructed using a standard Zope 3 IFactory
    named utility. By convention the factory utility has the same name as the
    portal_type of the content type.
-   
-   When a Dexterity FTI (Factory Type Information, see below) is created, 
-   an appropriate factory will be registered as a local utility unless one 
+
+   When a Dexterity FTI (Factory Type Information, see below) is created,
+   an appropriate factory will be registered as a local utility unless one
    with that name already exists.
-   
+
    The default factory is capable of initialising a generic 'Item' or
    'Container' object to exhibit a content type schema and have the
    security and other aspects specified in the type's model. You can use
@@ -170,17 +170,17 @@ The factory
 
 Views
 
-   Dexterity will by default create an add view (registered as a local 
+   Dexterity will by default create an add view (registered as a local
    utility, since it needs to take the portal_type of the content type into
    account when determining what fields to render) and an edit view (
    registered as a generic, global view, which inspects the context's
    portal_type at runtime) for each type. There is also a default main
    view, which simply outputs the fields set on the context.
-   
+
    To register new views, you will normally need a filesystem schema
    interface. You can then register views for this interface as you
    normally would.
-   
+
    If you need to override the default add view, create a view for IAdding
    with a name corresponding to the portal_type of the content type.
    This will prevent Dexterity from registering a local view with the same
@@ -191,21 +191,21 @@ The Factory Type Information (FTI)
    The FTI holds various information about the content type. Many operations
    performed by the Dexterity framework begin by looking up the type's
    FTI to find out some information about the type.
-   
+
    The FTI is an object stored in portal_types in the ZMI. Most settings can
    be changed through the web. See the IDexterityFTI interface for more
    information.
-   
+
    When a Dexterity FTI is created, an event handler will create a few
    local components, including the factory utility and add view for the
    new type. The FTI itself is also registered as a named utility, to
    make it easy to look up using syntax like:
-   
+
        getUtility(IDexterityFTI, name=portal_type)
-       
+
    The FTI is also fully importable and exportable using GenericSetup.
-   Thus, the easiest way to create and distribute a content type is to 
-   create a new FTI, set some properties (including a valid XML model, 
+   Thus, the easiest way to create and distribute a content type is to
+   create a new FTI, set some properties (including a valid XML model,
    which can be entered TTW if there is no file or schema interface to use),
    and export it as a GenericSetup extension profile.
 
@@ -214,24 +214,24 @@ Behaviours
    Behaviors are a way write make re-usable bits of functionality that can
    be toggled on or off on a per-type basis. Examples may include common
    metadata, or common functionality such as locking, tagging or ratings.
-   
+
    Behaviors are implemented using the plone.behavior package. See its
    documentation for more details about how to write your own behaviors.
-   
+
    In Dexterity, behaviors can "inject" fields into the standard add and edit
    forms, and may provide marker interfaces for newly created objects. See
    the example.dexterity package for an example of a behavior that provides
    form fields.
-   
+
    In use, a behavior is essentially just an adapter that only appears to be
    registered if the behavior is enabled in the FTI of the object being
    adapted. Thus, if you have a behavior described by my.package.IMyBehavior,
    you'll typically interact with this behavior by doing::
-   
+
        my_behavior = IMyBehavior(context, None)
        if my_behavior is not None:
            ...
-   
+
    The enabled behaviors for a given type are kept in the FTI, as a
    list of dotted interface names.
 
@@ -248,11 +248,11 @@ plone.alterego (Python)
 
    Support for dynamic modules that create objects on the fly. Dexterity
    uses this to dynamically create "real" interfaces for types that exist
-   only through-the-web. This allows these types to have a proper 
+   only through-the-web. This allows these types to have a proper
    IContentType schema, and allows local adapters to be registered for
-   this interface (e.g. a custom view with a template defined through the 
+   this interface (e.g. a custom view with a template defined through the
    web).
-   
+
    Note that if a type uses a filesystem interface (whether written manually
    or loaded from an XML model), this module is not used.
 
@@ -263,7 +263,7 @@ plone.supermodel (Zope 3)
    fields, and is thus easily extensible to new field types. This has the
    added benefit that the interface documentation in the zope.schema package
    applies to the XML format as well.
-   
+
    Supermodel is extensible via adapters and XML namespaces. plone.dexterity
    uses this to allow security and UI hints to be embedded as metadata in the
    XML model.
@@ -274,7 +274,7 @@ plone.behavior (Zope 3)
    a generic behaviour that works via a simple adapter. The adapter will
    appear to be registered for types that have the named behaviour
    available.
-   
+
    Dexterity wires this up in such a way that the list of enabled behaviours
    is stored as a property in the FTI. This makes it easy to add/remove
    behaviours through the web, or using GenericSetup at install time.
@@ -289,7 +289,7 @@ plone.autoform (CMF)
 
    Contains helper functions to construct forms based on tagged values stored
    on schema interfaces.
-   
+
 plone.directives.form (CMF)
 
    Adds convention-over-configuration support for plone.supermodel schemata
@@ -304,9 +304,9 @@ plone.dexterity (CMF)
 
 plone.directives.dexterity (CMF)
 
-   Adds convention-over-configuration support for Dexterity content and 
+   Adds convention-over-configuration support for Dexterity content and
    add/edit forms.
-   
+
 plone.app.dexterity (Plone)
 
    This package contains all Plone-specific aspects of Dexterity, including
@@ -315,7 +315,7 @@ plone.app.dexterity (Plone)
 Usage examples
 --------------
 
-Take a look at the example.dexterity package, which can be found in the 
+Take a look at the example.dexterity package, which can be found in the
 Plone Collective (http://dev.plone.org/collective), for examples of various
 ways to use Dexterity.
 
diff --git a/docs/INSTALL.txt b/docs/INSTALL.txt
index a2e8721..9110f2c 100644
--- a/docs/INSTALL.txt
+++ b/docs/INSTALL.txt
@@ -4,7 +4,7 @@ plone.dexterity Installation
 To install plone.dexterity into the global Python environment (or a workingenv),
 using a traditional Zope 2 instance, you can do this:
 
- * When you're reading this you have probably already run 
+ * When you're reading this you have probably already run
    ``easy_install plone.dexterity``. Find out how to install setuptools
    (and EasyInstall) here:
    http://peak.telecommunity.com/DevCenter/EasyInstall
@@ -20,24 +20,24 @@ Alternatively, if you are using zc.buildout and the plone.recipe.zope2instance
 recipe to manage your project, you can do this:
 
  * Add ``plone.dexterity`` to the list of eggs to install, e.g.:
- 
+
     [buildout]
     ...
     eggs =
         ...
         plone.dexterity
-        
+
   * Tell the plone.recipe.zope2instance recipe to install a ZCML slug:
-  
+
     [instance]
     recipe = plone.recipe.zope2instance
     ...
     zcml =
         plone.dexterity
-        
+
   * Re-run buildout, e.g. with:
-  
+
     $ ./bin/buildout
-        
+
 You can skip the ZCML slug if you are going to explicitly include the package
 from another package's configure.zcml file.
diff --git a/docs/LICENSE.txt b/docs/LICENSE.txt
index e493fe6..8a2ec36 100644
--- a/docs/LICENSE.txt
+++ b/docs/LICENSE.txt
@@ -11,5 +11,5 @@
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   MA 02111-1307 USA.
diff --git a/docs/WebDAV.txt b/docs/WebDAV.txt
index 3356f67..134d901 100644
--- a/docs/WebDAV.txt
+++ b/docs/WebDAV.txt
@@ -79,7 +79,7 @@ By default ``Resource.PUT()`` fails with 405 Method Not Allowed. That is, it
 is not by default possible to PUT to a resource that already exists. The same
 is true of ``Collection.PUT()``.
 
-In Dexterity, the ``PUT()`` method is overridden to adapt self to 
+In Dexterity, the ``PUT()`` method is overridden to adapt self to
 ``zope.filerepresentation.IRawWriteFile``, and call its ``write()`` method one
 or more times, writing the contents of the request body, before calling
 ``close()``. The ``mimeType`` and ``encoding`` properties will also be set
@@ -149,7 +149,7 @@ status.
 
 The ``PropertyManager`` mixin class defines the ``propertysheets`` variable to
 be an instance of ``DefaultPropertySheets``. This in turn has two property
-sheets, ``default``, a ``DefaultProperties`` instance, and ``webdav``, a 
+sheets, ``default``, a ``DefaultProperties`` instance, and ``webdav``, a
 ``DAVProperties`` instance.
 
 The ``DefaultProperties`` instance contains the main property sheet. This
diff --git a/plone/dexterity/CONVENTIONS.txt b/plone/dexterity/CONVENTIONS.txt
index 8ae5213..690e296 100644
--- a/plone/dexterity/CONVENTIONS.txt
+++ b/plone/dexterity/CONVENTIONS.txt
@@ -4,28 +4,28 @@ Dexterity naming conventions
 The following naming conventions apply to Dexterity code.
 
  * Classes use CamelCase, e.g. SchemaFactory
- 
+
  * Methods and functions that are meant for external use are in mixedCase,
    e.g. createContentInContainer()
-   
+
  * Arguments to methods that are meant for external use are also in mixedCase,
    e.g. addContentToContainer(container, object, checkConstraints=True)
-  
+
  * Class variables and object attributes that are meant for external use
    are also in mixedCase, e.g. isPrincipiaFolderish
-   
+
  * Exceptions to this rule:
- 
+
      * FTI attributes are in lower_case_with_underscore, e.g. model_source
      * Any attribute/argument referring to the CMF portal_type is written as
        such, *not* portalType
- 
+
  * Acronyms in class or variable names are all in the same case, e.g.
    DexterityFTI or ftiCounter.
-   
+
  * Constants and globals are in ALL_CAPS_WITH_UNDER_SCORE e.g. SCHEMA_CACHE
 
  * Internal variables may be in lower_case_with_underscore if appropriate.
 
- * Grok directives use lower_case_and_underscore, e.g. 
+ * Grok directives use lower_case_and_underscore, e.g.
    dexterity.write_permission() or form.default_value().
\ No newline at end of file
diff --git a/plone/dexterity/behavior.py b/plone/dexterity/behavior.py
index c9d2c99..64fb719 100644
--- a/plone/dexterity/behavior.py
+++ b/plone/dexterity/behavior.py
@@ -10,19 +10,19 @@
 class DexterityBehaviorAssignable(object):
     """Support plone.behavior behaviors stored in the FTI
     """
-    
+
     implements(IBehaviorAssignable)
     adapts(IDexterityContent)
-    
+
     def __init__(self, context):
         self.fti = getUtility(IDexterityFTI, name=context.portal_type)
-    
+
     def supports(self, behavior_interface):
         for behavior in self.enumerateBehaviors():
             if behavior_interface in behavior.interface._implied:
                 return True
         return False
-        
+
     def enumerateBehaviors(self):
         for name in self.fti.behaviors:
             behavior = queryUtility(IBehavior, name=name)
diff --git a/plone/dexterity/browser/add.py b/plone/dexterity/browser/add.py
index 9ffb6ec..ab8499b 100644
--- a/plone/dexterity/browser/add.py
+++ b/plone/dexterity/browser/add.py
@@ -21,37 +21,37 @@
 
 class DefaultAddForm(DexterityExtensibleForm, form.AddForm):
     """Standard add form, which is wrapped by DefaultAddView (see below).
-    
+
     This form is capable of rendering the fields of any Dexterity schema,
     including behaviours. To do that, needs to know the portal_type, which
     can be set as a class variable (in a subclass), or on a created instance.
-    
+
     By default, the DefaultAddView (see below) will set the portal_type based
     on the FTI.
     """
-    
+
     portal_type = None
     immediate_view = None
-    
+
     def __init__(self, context, request, ti=None):
         super(DefaultAddForm, self).__init__(context, request)
         if ti is not None:
             self.ti = ti
             self.portal_type = ti.getId()
         self.request['disable_border'] = True
-    
+
     @property
     def additionalSchemata(self):
         return getAdditionalSchemata(portal_type=self.portal_type)
 
     # API
-    
+
     def create(self, data):
         fti = getUtility(IDexterityFTI, name=self.portal_type)
-        
+
         container = aq_inner(self.context)
         content = createObject(fti.factory)
-        
+
         # Note: The factory may have done this already, but we want to be sure
         # that the created type has the right portal type. It is possible
         # to re-define a type through the web that uses the factory from an
@@ -59,7 +59,7 @@ def create(self, data):
 
         if hasattr(content, '_setPortalTypeName'):
             content._setPortalTypeName(fti.getId())
-        
+
         # Acquisition wrap temporarily to satisfy things like vocabularies
         # depending on tools
         if IAcquirer.providedBy(content):
@@ -72,11 +72,11 @@ def create(self, data):
         return aq_base(content)
 
     def add(self, object):
-        
+
         fti = getUtility(IDexterityFTI, name=self.portal_type)
         container = aq_inner(self.context)
         new_object = addContentToContainer(container, object)
-        
+
         if fti.immediate_view:
             self.immediate_view = "%s/%s/%s" % (container.absolute_url(), new_object.id, fti.immediate_view,)
         else:
@@ -87,9 +87,9 @@ def nextURL(self):
             return self.immediate_view
         else:
             return self.context.absolute_url()
-    
+
     # Buttons
-    
+
     @button.buttonAndHandler(_('Save'), name='save')
     def handleAdd(self, action):
         data, errors = self.extractData()
@@ -101,24 +101,24 @@ def handleAdd(self, action):
             # mark only as finished if we get the new object
             self._finishedAdd = True
             IStatusMessage(self.request).addStatusMessage(_(u"Item created"), "info success")
-    
+
     @button.buttonAndHandler(_(u'Cancel'), name='cancel')
     def handleCancel(self, action):
         IStatusMessage(self.request).addStatusMessage(_(u"Add New Item operation cancelled"), "info")
         self.request.response.redirect(self.nextURL())
         notify(AddCancelledEvent(self.context))
-    
+
     def update(self):
         super(DefaultAddForm, self).update()
         # fire the edit begun only if no action was executed
         if len(self.actions.executedActions) == 0:
             notify(AddBegunEvent(self.context))
-    
+
     def updateActions(self):
         super(DefaultAddForm, self).updateActions()
         if 'save' in self.actions:
             self.actions["save"].addClass("context")
-        
+
         if 'cancel' in self.actions:
             self.actions["cancel"].addClass("standalone")
 
@@ -132,19 +132,19 @@ def label(self):
 
 class DefaultAddView(layout.FormWrapper, BrowserPage):
     """This is the default add view as looked up by the ++add++ traversal
-    namespace adapter in CMF. It is an unnamed adapter on 
+    namespace adapter in CMF. It is an unnamed adapter on
     (context, request, fti).
-    
+
     Note that this is registered in ZCML as a simple <adapter />, but we
     also use the <class /> directive to set up security.
     """
-    
+
     form = DefaultAddForm
-    
+
     def __init__(self, context, request, ti):
         super(DefaultAddView, self).__init__(context, request)
         self.ti = ti
 
         # Set portal_type name on newly created form instance
-        if self.form_instance is not None and not getattr(self.form_instance, 'portal_type', None): 
+        if self.form_instance is not None and not getattr(self.form_instance, 'portal_type', None):
             self.form_instance.portal_type = ti.getId()
diff --git a/plone/dexterity/browser/configure.zcml b/plone/dexterity/browser/configure.zcml
index 3c806d2..5dbf341 100644
--- a/plone/dexterity/browser/configure.zcml
+++ b/plone/dexterity/browser/configure.zcml
@@ -2,7 +2,7 @@
     xmlns="http://namespaces.zope.org/zope"
     xmlns:browser="http://namespaces.zope.org/browser"
     i18n_domain="plone.dexterity">
-  
+
     <!-- Standard view -->
     <browser:page
         for="..interfaces.IDexterityContent"
@@ -11,7 +11,7 @@
         template="item.pt"
         permission="zope2.View"
         />
-    
+
     <!-- Content core views -->
 
     <browser:page
@@ -32,7 +32,7 @@
 
     <!-- Standard IPublishTraverse adapter -->
     <adapter factory=".traversal.DexterityPublishTraverse" />
-    
+
     <!-- Standard add view and form - invoked from ++add++ traverser -->
     <adapter
         for="Products.CMFCore.interfaces.IFolderish
@@ -55,7 +55,7 @@
         class=".edit.DefaultEditView"
         permission="cmf.ModifyPortalContent"
         />
-  
+
     <!-- FTI add form -->
     <browser:page
         for="zope.browser.interfaces.IAdding"
@@ -64,14 +64,14 @@
         class=".fti.FTIAddView"
         permission="cmf.ManagePortal"
         />
-        
+
     <!-- Resources for icons -->
-    
+
     <browser:resource
         name="plone.dexterity.item.gif"
         file="icons/item_icon.gif"
         />
-    
+
     <browser:resource
         name="plone.dexterity.container.gif"
         file="icons/container_icon.gif"
@@ -80,6 +80,6 @@
     <browser:resource
         name="plone.dexterity.fti.gif"
         file="icons/typeinfo.gif"
-        />  
+        />
 
 </configure>
\ No newline at end of file
diff --git a/plone/dexterity/browser/containercontentcore.pt b/plone/dexterity/browser/containercontentcore.pt
index 911012a..f95d8e8 100644
--- a/plone/dexterity/browser/containercontentcore.pt
+++ b/plone/dexterity/browser/containercontentcore.pt
@@ -7,7 +7,7 @@
           <div tal:content="structure widget/render" />
       </div>
   </tal:block>
-          
+
   <fieldset tal:repeat="group view/groups"
             tal:attributes="id python:''.join((group.prefix, 'groups.', group.__name__)).replace('.', '-')">
       <legend tal:content="group/label" />
@@ -17,7 +17,7 @@
           <div tal:content="structure widget/render" />
       </div>
   </fieldset>
-  
+
   <fieldset id="folder-listing">
       <legend>Contents</legend>
       <tal:block define="listing_macro context/folder_listing/macros/listing">
diff --git a/plone/dexterity/browser/edit.py b/plone/dexterity/browser/edit.py
index deec09c..4447771 100644
--- a/plone/dexterity/browser/edit.py
+++ b/plone/dexterity/browser/edit.py
@@ -19,7 +19,7 @@
 
 
 class DefaultEditForm(DexterityExtensibleForm, form.EditForm):
-    
+
     @button.buttonAndHandler(_(u'Save'), name='save')
     def handleApply(self, action):
         data, errors = self.extractData()
@@ -30,7 +30,7 @@ def handleApply(self, action):
         IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"), "info success")
         self.request.response.redirect(self.nextURL())
         notify(EditFinishedEvent(self.context))
-    
+
     @button.buttonAndHandler(_(u'Cancel'), name='cancel')
     def handleCancel(self, action):
         IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"), "info")
@@ -48,32 +48,32 @@ def nextURL(self):
                 if portal_type in use_view_action:
                     view_url = view_url + '/view'
         return view_url
-    
+
     def update(self):
         self.portal_type = self.context.portal_type
         super(DefaultEditForm, self).update()
-        
+
         # fire the edit begun only if no action was executed
         if len(self.actions.executedActions) == 0:
             notify(EditBegunEvent(self.context))
 
     def updateActions(self):
         super(DefaultEditForm, self).updateActions()
-        
+
         if 'save' in self.actions:
             self.actions["save"].addClass("context")
-        
+
         if 'cancel' in self.actions:
             self.actions["cancel"].addClass("standalone")
 
     @property
     def fti(self):
         return getUtility(IDexterityFTI, name=self.portal_type)
-    
+
     @property
     def label(self):
         type_name = self.fti.Title()
         return _(u"Edit ${name}", mapping={'name': type_name})
-        
+
 DefaultEditView = layout.wrap_form(DefaultEditForm)
 classImplements(DefaultEditView, IDexterityEditForm)
diff --git a/plone/dexterity/browser/fti.pt b/plone/dexterity/browser/fti.pt
index 09a83a4..728200e 100644
--- a/plone/dexterity/browser/fti.pt
+++ b/plone/dexterity/browser/fti.pt
@@ -37,7 +37,7 @@
     
   </td>
   <td>
-   <input class="form-element" type="submit" name="submit_add" value="Add" /> 
+   <input class="form-element" type="submit" name="submit_add" value="Add" />
   </td>
  </tr>
 </table>
diff --git a/plone/dexterity/browser/item.pt b/plone/dexterity/browser/item.pt
index 137a8a2..b42a994 100644
--- a/plone/dexterity/browser/item.pt
+++ b/plone/dexterity/browser/item.pt
@@ -9,7 +9,7 @@
 
 <metal:main fill-slot="main">
 
-    <h1 class="documentFirstHeading" tal:content="context/Title" /> 
+    <h1 class="documentFirstHeading" tal:content="context/Title" />
 
     <p class="documentDescription" tal:content="context/Description" />
 
@@ -20,7 +20,7 @@
             <div tal:content="structure widget/render" />
         </div>
     </tal:block>
-            
+
     <fieldset tal:repeat="group view/groups"
               tal:attributes="id python:''.join((group.prefix, 'groups.', group.__name__)).replace('.', '-')">
         <legend tal:content="group/label" />
diff --git a/plone/dexterity/browser/itemcontentcore.pt b/plone/dexterity/browser/itemcontentcore.pt
index 6e453b6..2e07bdf 100644
--- a/plone/dexterity/browser/itemcontentcore.pt
+++ b/plone/dexterity/browser/itemcontentcore.pt
@@ -7,7 +7,7 @@
           <div tal:content="structure widget/render" />
       </div>
   </tal:block>
-          
+
   <fieldset tal:repeat="group view/groups"
             tal:attributes="id python:''.join((group.prefix, 'groups.', group.__name__)).replace('.', '-')">
       <legend tal:content="group/label" />
diff --git a/plone/dexterity/browser/traversal.py b/plone/dexterity/browser/traversal.py
index f677275..3234d73 100644
--- a/plone/dexterity/browser/traversal.py
+++ b/plone/dexterity/browser/traversal.py
@@ -19,34 +19,34 @@
 class DexterityPublishTraverse(DefaultPublishTraverse):
     """Override the default browser publisher to make WebDAV work for
     Dexterity objects.
-    
+
     In part, this works around certain problems with the ZPublisher that make
     DAV requests difficult, and in part it adds support for the '_data'
     pseudo-resource that is shown for folderish content items.
     """
-    
+
     adapts(IDexterityContent, IBrowserRequest)
-    
+
     def __init__(self, context, request):
         self.context = context
         self.request = request
-    
+
     def publishTraverse(self, request, name):
-        
+
         context = aq_inner(self.context)
-        
-        # If we are trying to traverse to the folder "body" pseudo-object 
+
+        # If we are trying to traverse to the folder "body" pseudo-object
         # returned by listDAVObjects(), return that immediately
 
         if getattr(request, 'maybe_webdav_client', False) and name == DAV_FOLDER_DATA_ID:
             return FolderDataResource(DAV_FOLDER_DATA_ID, context).__of__(context)
-        
+
         defaultTraversal = super(DexterityPublishTraverse, self).publishTraverse(request, name)
-        
+
         # If this is a WebDAV PUT/PROPFIND/PROPPATCH request, don't acquire
         # things. If we did, we couldn't create a new object with PUT, for
         # example, because the acquired object would shadow the NullResource
-        
+
         if (getattr(request, 'maybe_webdav_client', False)               and
             request.get('REQUEST_METHOD', 'GET') not in ('GET', 'POST',) and
             IAcquirer.providedBy(defaultTraversal)
@@ -54,18 +54,18 @@ def publishTraverse(self, request, name):
             parent = aq_parent(aq_inner(defaultTraversal))
             if parent is not None and parent is not context:
                 return NullResource(self.context, name, request).__of__(self.context)
-        
+
         return defaultTraversal
-    
+
     def browserDefault(self, request):
-        
-        # If this is not a WebDAV request, we don't want to give a 
+
+        # If this is not a WebDAV request, we don't want to give a
         # default view. The ZPublisher's WebDAV implementation doesn't
         # deal well with default views.
-        
+
         if (getattr(request, 'maybe_webdav_client', False) and
             request.get('REQUEST_METHOD', 'GET') not in ('GET', 'POST',)
         ):
             return self.context, ()
-        
+
         return super(DexterityPublishTraverse, self).browserDefault(request)
diff --git a/plone/dexterity/configure.zcml b/plone/dexterity/configure.zcml
index 839b106..51f28db 100644
--- a/plone/dexterity/configure.zcml
+++ b/plone/dexterity/configure.zcml
@@ -14,29 +14,29 @@
     <include package="plone.rfc822" />
     <include package="plone.uuid" />
     <include package="plone.z3cform" />
-    
+
     <include package=".browser" />
     <include package=".fti" />
-    
+
     <!-- Re-index content when it's modified -->
     <subscriber
         for=".interfaces.IDexterityContent
              zope.lifecycleevent.interfaces.IObjectModifiedEvent"
         handler=".content.reindexOnModify"
         />
-    
+
     <!-- Support for dynamic schemata -->
-    
+
     <utility
         factory=".schema.DexteritySchemaPolicy"
         name="dexterity"
         />
-        
+
     <utility
         factory=".schema.SchemaModuleFactory"
         name="plone.dexterity.schema.generated"
         />
-                
+
     <!-- Schema cache -->
     <subscriber handler=".schema.invalidate_schema" />
 
@@ -51,7 +51,7 @@
         icon="plone.dexterity.item.gif"
         />
     <class class=".content.Item" />
-        
+
     <five:registerClass
         class=".content.Container"
         meta_type="Dexterity Container"
@@ -59,7 +59,7 @@
         icon="plone.dexterity.item.gif"
         />
     <class class=".content.Container" />
-        
+
     <!-- Register FTI class -->
     <five:registerClass
         class=".fti.DexterityFTI"
@@ -69,37 +69,37 @@
         icon="plone.dexterity.fti.gif"
         global="False"
         />
-        
+
     <!-- Register FTI add/remove/modify handlers -->
-    
+
     <subscriber
         for=".interfaces.IDexterityFTI
              zope.container.interfaces.IObjectAddedEvent"
         handler=".fti.ftiAdded"
         />
-        
+
     <subscriber
         for=".interfaces.IDexterityFTI
              zope.container.interfaces.IObjectRemovedEvent"
         handler=".fti.ftiRemoved"
         />
-        
+
     <subscriber
         for=".interfaces.IDexterityFTI
              zope.container.interfaces.IObjectMovedEvent"
         handler=".fti.ftiRenamed"
         />
-    
+
     <subscriber
         for=".interfaces.IDexterityFTI
              zope.lifecycleevent.interfaces.IObjectModifiedEvent"
         handler=".fti.ftiModified"
         />
-    
+
     <!-- File representation (FTP/WebDAV support) -->
     <adapter factory=".filerepresentation.DefaultDirectoryFactory" />
     <adapter factory=".filerepresentation.DefaultFileFactory" />
-    
+
     <adapter
         provides="zope.filerepresentation.interfaces.IRawReadFile"
         factory=".filerepresentation.DefaultReadFile"
diff --git a/plone/dexterity/factory.py b/plone/dexterity/factory.py
index 3f3eb74..0ee070e 100644
--- a/plone/dexterity/factory.py
+++ b/plone/dexterity/factory.py
@@ -12,11 +12,11 @@
 from plone.dexterity.utils import resolveDottedName
 
 class DexterityFactory(Persistent, Factory):
-    """A factory for Dexterity content. 
+    """A factory for Dexterity content.
     """
-    
+
     implements(IDexterityFactory)
-    
+
     def __init__(self, portal_type):
         self.portal_type = portal_type
 
@@ -32,16 +32,16 @@ def description(self):
 
     def __call__(self, *args, **kw):
         fti = getUtility(IDexterityFTI, name=self.portal_type)
-        
+
         klass = resolveDottedName(fti.klass)
         if klass is None or not callable(klass):
             raise ValueError("Content class %s set for type %s is not valid" % (fti.klass, self.portal_type))
-        
+
         try:
             obj = klass(*args, **kw)
         except TypeError, e:
             raise ValueError("Error whilst constructing content for %s using class %s: %s" % (self.portal_type, fti.klass, str(e)))
-        
+
         # Set portal_type if not set, but avoid creating an instance variable
         # if possible
         if getattr(obj, 'portal_type', '') != self.portal_type:
diff --git a/plone/dexterity/filerepresentation.py b/plone/dexterity/filerepresentation.py
index 7eb322e..f3ada88 100644
--- a/plone/dexterity/filerepresentation.py
+++ b/plone/dexterity/filerepresentation.py
@@ -41,15 +41,15 @@
 
 class DAVResourceMixin(object):
     """Mixin class for WebDAV resource support.
-    
+
     The main purpose of this class is to implement the Zope 2 WebDAV API to
     delegate to more granular adapters.
     """
-    
+
     def get_size(self):
         """Get the size of the content item in bytes. Used both in folder
         listings and in DAV PROPFIND requests.
-        
+
         The default implementation delegates to an ISized adapter and calls
         getSizeForSorting(). This returns a tuple (unit, value). If the unit
         is 'bytes', the value is returned, otherwise the size is 0.
@@ -61,7 +61,7 @@ def get_size(self):
         if unit == 'bytes':
             return size
         return 0
-    
+
     def content_type(self):
         """Return the content type (MIME type) of the tiem
         """
@@ -69,105 +69,105 @@ def content_type(self):
         if readFile is None:
             return None
         return readFile.mimeType
-    
+
     def Format(self):
         """Return the content type (MIME type) of the item
         """
         return self.content_type()
-    
+
     def manage_DAVget(self):
         """Get the body of the content item in a WebDAV response.
         """
         return self.manage_FTPget()
-    
+
     def manage_FTPget(self, REQUEST=None, RESPONSE=None):
         """Return the body of the content item in an FTP or WebDAV response.
-        
+
         This adapts self to IRawReadFile(), which is then returned as an
         iterator. The adapter should provide IStreamIterator.
         """
         reader = IRawReadFile(self, None)
         if reader is None:
             return ''
-        
+
         request = REQUEST is not None and REQUEST or self.REQUEST
         response = RESPONSE is not None and RESPONSE or request.response
-        
+
         mimeType = reader.mimeType
         encoding = reader.encoding
-        
+
         if mimeType is not None:
             if encoding is not None:
                 response.setHeader('Content-Type', '%s; charset="%s"' % (mimeType, encoding,))
             else:
                 response.setHeader('Content-Type', mimeType)
-        
+
         size = reader.size()
         if size is not None:
             response.setHeader('Content-Length', str(size))
-        
+
         # if the reader is an iterator that the publisher can handle, return
         # it as-is. Otherwise, read the full contents
-        
+
         if ((IInterface.providedBy(IStreamIterator) and IStreamIterator.providedBy(reader))
          or (not IInterface.providedBy(IStreamIterator) and IStreamIterator.isImplementedBy(reader))
         ):
             return reader
         else:
             return reader.read()
-    
+
     def PUT(self, REQUEST=None, RESPONSE=None):
         """WebDAV method to replace self with a new resource. This is also
         used when initialising an object just created from a NullResource.
-        
+
         This will look up an IRawWriteFile adapter on self and write to it,
         line-by-line, from the request body.
         """
         request = REQUEST is not None and REQUEST or self.REQUEST
         response = RESPONSE is not None and RESPONSE or request.response
-        
+
         self.dav__init(request, response)
         self.dav__simpleifhandler(request, response, refresh=1)
-        
+
         infile = request.get('BODYFILE', None)
         if infile is None:
             raise MethodNotAllowed("Cannot complete PUT request: No BODYFILE in request")
-        
+
         writer = IRawWriteFile(self, None)
         if writer is None:
             raise MethodNotAllowed("Cannot complete PUT request: No IRawWriteFile adapter found")
-        
+
         contentTypeHeader = request.get_header('content-type', None)
-        
+
         if contentTypeHeader is not None:
             msg = Message()
             msg['Content-Type'] = contentTypeHeader
-            
+
             mimeType = msg.get_content_type()
             if mimeType is not None:
                 writer.mimeType = mimeType
-            
+
             charset = msg.get_param('charset')
             if charset is not None:
                 writer.encoding = charset
-        
+
         try:
             for chunk in infile:
                 writer.write(chunk)
         finally:
             writer.close()
-        
+
         modified(self)
         return response
 
 
 class DAVCollectionMixin(DAVResourceMixin):
     """Mixin class for WebDAV collection support.
-    
+
     The main purpose of this class is to implement the Zope 2 WebDAV API to
     delegate to more granular adapters.
     """
-    
+
     def MKCOL_handler(self, id, REQUEST=None, RESPONSE=None):
         """Handle "make collection" by delegating to an IDirectoryFactory
         adapter.
@@ -176,7 +176,7 @@ def MKCOL_handler(self, id, REQUEST=None, RESPONSE=None):
         if factory is None:
             raise MethodNotAllowed("Cannot create collection: No IDirectoryFactory adapter found")
         factory(id)
-    
+
     def PUT_factory(self, name, contentType, body):
         """Handle constructing a new object upon a PUT request by delegating
         to an IFileFactory adapter
@@ -185,10 +185,10 @@ def PUT_factory(self, name, contentType, body):
         if factory is None:
             return None
         return factory(name, contentType, body)
-    
+
     def listDAVObjects(self):
         """Return objects for WebDAV folder listings.
-        
+
         We add a non-folderish pseudo object which contains the "body" data
         for this container.
         """
@@ -197,7 +197,7 @@ def listDAVObjects(self):
             parentList = []
         else:
             parentList = list(parentList)
-        
+
         # insert the FolderDataResource pseudo child
         faux = FolderDataResource(DAV_FOLDER_DATA_ID, self).__of__(self)
         parentList.insert(0, faux)
@@ -207,28 +207,28 @@ def listDAVObjects(self):
 class FolderDataResource(Implicit, Resource):
     """This object is a proxy which is created on-demand during traversal,
     to allow access to the "file-like" aspects of a container type.
-    
+
     When a Container object is listed via WebDAV, the first item in the folder
     listing is an instance of this class with an id of '_data'. When
     requested, the default Dexterity IPublishTraverse adapter will also return
     an instance (the instances are non-persistent). A GET, PUT, HEAD, LOCK,
-    UNLOCK, PROPFIND or PROPPATCH request against this resource will be 
+    UNLOCK, PROPFIND or PROPPATCH request against this resource will be
     treated as if it were a request against the parent object, treating it
     as a resource (file) rather than a collection (folder).
     """
-    
+
     __dav_collection__ = 0
-    
+
     def __init__(self, name, parent):
         self.__dict__.update({'__parent__': parent, '__name__': name})
-    
+
     # We need to proxy certain things to the parent for getting and setting
     # of property sheet values to work.
-    # 
+    #
     # XXX: A better approach may be to define a custom PropertySheets type
     # with some kind of wrapping property sheet that redefines v_self() to
     # be the container.
-    
+
     def __getattr__(self, name):
         """Fall back on parent for certain things, even if we're aq_base'd.
         This makes propertysheet access work.
@@ -236,7 +236,7 @@ def __getattr__(self, name):
         if hasattr(self.__parent__.aq_base, name):
             return getattr(self.__parent__, name)
         raise AttributeError(name)
-    
+
     def __setattr__(self, name, value):
         """Set certain attributes on the parent
         """
@@ -246,101 +246,101 @@ def __setattr__(self, name, value):
             setattr(self.__parent__, name, value)
         else:
             object.__setattr__(self, name, value)
-    
+
     @property
     def _properties(self):
         return self.__parent__._properties
 
     @_properties.setter
     def _properties(self, value):
-        self.__parent__._properties = value        
-    
+        self.__parent__._properties = value
+
     @property
     def id(self):
         return self.__name__
-    
+
     def getId(self):
         """Get id for traveral purposes
         """
         return self.__name__
-        
+
     def HEAD(self, REQUEST, RESPONSE):
         """HEAD request: use the Resource algorithm on the data of the
         parent.
         """
         return Resource.HEAD(self.__parent__, REQUEST, RESPONSE)
-    
+
     def OPTIONS(self, REQUEST, RESPONSE):
         """OPTIONS request: delegate to parent
         """
         return self.__parent__.OPTIONS(REQUEST, RESPONSE)
-    
+
     def TRACE(self, REQUEST, RESPONSE):
         """TRACE request: delegate to parent
         """
         return self.__parent__.TRACE(REQUEST, RESPONSE)
-    
+
     def PROPFIND(self, REQUEST, RESPONSE):
         """PROPFIND request: use Resource algorithm on self, so that we do
         not appear as a folder.
-        
+
         Certain things may be acquired, notably .propertysheets
         """
         return super(FolderDataResource, self).PROPFIND(REQUEST, RESPONSE)
-    
+
     def PROPPATCH(self, REQUEST, RESPONSE):
         """PROPPATCH request: Use Resource algorithm on self, so that we do
         not appear as a folder.
-        
+
         Certain things may be acquired, notably .propertysheets
         """
         return super(FolderDataResource, self).PROPPATCH(REQUEST, RESPONSE)
-    
+
     def LOCK(self, REQUEST, RESPONSE):
         """LOCK request: delegate to parent
         """
         return self.__parent__.LOCK(REQUEST, RESPONSE)
-    
+
     def UNLOCK(self, REQUEST, RESPONSE):
         """UNLOCK request: delegate to parent
         """
         return self.__parent__.UNLOCK(REQUEST, RESPONSE)
-    
+
     def PUT(self, REQUEST, RESPONSE):
         """PUT request: delegate to parent
         """
         return self.__parent__.PUT(REQUEST, RESPONSE)
-    
+
     def MKCOL(self, REQUEST, RESPONSE):
         """MKCOL request: not allowed
         """
         raise MethodNotAllowed('Cannot create a collection inside a folder data: try at the folder level instead')
-    
+
     def DELETE(self, REQUEST, RESPONSE):
         """DELETE request: not allowed
         """
         raise MethodNotAllowed('Cannot delete folder data: delete folder instead')
-    
+
     def COPY(self, REQUEST, RESPONSE):
         """COPY request: not allowed
         """
         raise MethodNotAllowed('Cannot copy folder data: copy the folder instead')
-        
+
     def MOVE(self, REQUEST, RESPONSE):
         """MOVE request: not allowed
         """
         raise MethodNotAllowed('Cannot move folder data: move the folder instead')
-    
+
     def manage_DAVget(self):
         """DAV content access: delete to manage_FTPget()
         """
         return self.__parent__.manage_DAVget()
-    
+
     def manage_FTPget(self):
         """FTP access: delegate to parent
         """
         return self.__parent__.manage_FTPget()
-    
+
     def listDAVObjects(self):
         """DAV object listing: return nothing
         """
@@ -351,39 +351,39 @@ class StringStreamIterator(object):
     """Simple stream iterator to allow efficient data streaming.
     """
     implements(IStreamIterator)
-    
+
     def __init__(self, data, size=None, chunk=1<<16):
         """Consume data (a str) into a temporary file and prepare streaming.
-        
+
         size is the length of the data. If not given, the length of the data
         string is used.
-        
+
         chunk is the chunk size for the iterator
         """
         f = tempfile.TemporaryFile(mode='w+b')
         f.write(data)
-        
+
         if size is not None:
             assert size == f.tell(), 'Size argument does not match data length'
         else:
             size = f.tell()
-        
+
         f.seek(0)
-        
+
         self.file = f
         self.size = size
         self.chunk = chunk
-    
+
     def __iter__(self):
         return self
-    
+
     def next(self):
         data = self.file.read(self.chunk)
         if not data:
             self.file.close()
             raise StopIteration
         return data
-    
+
     def __len__(self):
         return self.size
 
@@ -391,16 +391,16 @@ def __len__(self):
 class DefaultDirectoryFactory(object):
     """Default directory factory, invoked when an FTP/WebDAV operation
     attempts to create a new folder via a MKCOL request.
-    
+
     The default implementation simply calls manage_addFolder().
     """
-    
+
     implements(IDirectoryFactory)
     adapts(IDexterityContainer)
-    
+
     def __init__(self, context):
         self.context = context
-    
+
     def __call__(self, name):
         self.context.manage_addFolder(name)
 
@@ -408,40 +408,40 @@ def __call__(self, name):
 class DefaultFileFactory(object):
     """Default file factory, invoked when an FTP/WebDAV operation
     attempts to create a new resource via a PUT request.
-    
+
     The default implementation uses the content_type_registry to find a
     type to add, and then creates an instance using the portal_types
     tool.
     """
-    
+
     implements(IFileFactory)
     adapts(IDexterityContainer)
-    
+
     def __init__(self, context):
         self.context = context
-    
+
     def __call__(self, name, contentType, data):
-        
+
         # Deal with Finder cruft
         if name == '.DS_Store':
             raise Unauthorized("Refusing to store Mac OS X resource forks")
         elif name.startswith('._'):
             raise Unauthorized("Refusing to store Mac OS X resource forks")
-        
+
         registry = getToolByName(self.context, 'content_type_registry', None)
         if registry is None:
             return None # fall back on default
-        
+
         typeObjectName = registry.findTypeName(name, contentType, data)
         if typeObjectName is None:
             return # fall back on default
-        
+
         typesTool = getToolByName(self.context, 'portal_types')
-        
+
         targetType = typesTool.getTypeInfo(typeObjectName)
         if targetType is None:
             return # fall back on default
-        
+
         # There are two possibilities here: either we have a new-style
         # IFactory utility, in which case all is good. We can call the
         # factory and return the object. Or, we have an old style factory
@@ -450,58 +450,58 @@ def __call__(self, name, contentType, data):
         # object, before re-creating it immediately afterwards in
         # NullResource.PUT(). Naturally this sucks. At least, let's do the
         # sane thing for content with new-style factories.
-        
+
         if targetType.product: # boo :(
-            
+
             newName = self.context.invokeFactory(typeObjectName, name)
             obj = aq_base(self.context._getOb(newName))
             self.context._delObject(newName)
             return obj
-            
+
         else: # yay
-            
+
             contextType = typesTool.getTypeInfo(self.context)
             if contextType is not None:
                 if not contextType.allowType(typeObjectName):
                     raise Unauthorized("Creating a %s object here is not allowed" % typeObjectName)
-            
+
             if not targetType.isConstructionAllowed(self.context):
                 raise Unauthorized("Creating a %s object here is not allowed" % typeObjectName)
-            
+
             obj = createObject(targetType.factory)
-            
+
             if hasattr(obj, '_setPortalTypeName'):
                 obj._setPortalTypeName(targetType.getId())
-            
+
             # we fire this event here, because NullResource.PUT will now go
             # and set the object on the parent. The correct sequence of
             # events is object created -> object added. In this case, we'll
             # get object created -> object added -> object modified.
             notify(ObjectCreatedEvent(obj))
-        
+
         return obj
 
 class ReadFileBase(object):
     """Convenience base class for read files which delegate to another stream
     type (e.g. a temporary file or StringIO)
-    
+
     Override _getStream() and any required methods.
     """
-    
+
     implements(IRawReadFile)
-    
+
     def __init__(self, context):
         self.context = context
         self._size = 0
-    
+
     mimeType = None
     encoding = 'utf-8'
     name = None
-    
+
     @property
     def closed(self):
         return self._getStream().closed
-    
+
     def size(self):
         stream = self._getStream()
         pos = stream.tell()
@@ -509,64 +509,64 @@ def size(self):
         size = stream.tell()
         stream.seek(pos)
         return size
-    
+
     def seek(self, offset, whence=None):
         if whence is not None:
             self._getStream().seek(offset, whence)
         else:
             self._getStream().seek(offset)
-    
+
     def tell(self):
         return self._getStream().tell()
-    
+
     def close(self):
         self._getStream().close()
-    
+
     def read(self, size=None):
         if size is not None:
             return self._getStream().read(size)
         else:
             return self._getStream().read()
-    
+
     def readline(self, size=None):
         if size is None:
             return self._getStream().readline()
         else:
             return self._getStream().readline(size)
-    
+
     def readlines(self, sizehint=None):
         if sizehint is None:
             return self._getStream().readlines()
         else:
             return self._getStream().readlines(sizehint)
-    
+
     def __iter__(self):
         return self
-    
+
     def next(self):
         return self._getStream().next()
-    
+
     def _getStream(self):
         raise NotImplementedError("Subclass and override this _getStream()")
 
 
 class DefaultReadFile(ReadFileBase):
     """IRawReadFile adapter for Dexterity objects.
-    
+
     Uses RFC822 marshaler.
-    
+
     This is also marked as an IStreamIterator, which means that it is safe
     to return it to the publisher directly. In particular, the size() method
     will return an accurate file size.
     """
-    
+
     implements(IStreamIterator)
     adapts(IDexterityContent)
-    
+
     def __init__(self, context):
         self.context = context
         self._haveMessage = False
-    
+
     @property
     def mimeType(self):
         if not self._haveMessage:
@@ -585,33 +585,33 @@ def mimeType(self):
             return 'text/plain'
         else:
             return 'message/rfc822'
-    
+
     @property
     def encoding(self):
         return self._getMessage().get_charset() or 'utf-8'
-    
+
     @property
     def name(self):
         return self._getMessage().get_filename(None)
-    
+
     def size(self):
         # construct the stream if necessary
         self._getStream()
         return self._size
-    
+
     # internal helper methods
-    
+
     @memoize
     def _getMessage(self):
         """Construct message on demand
         """
         message = constructMessageFromSchemata(self.context, iterSchemata(self.context))
-        
+
         # Store the portal type in a header, to allow it to be identifed later
         message['Portal-Type'] = self.context.portal_type
-        
+
         return message
-    
+
     @memoize
     def _getStream(self):
         # We write to a TemporayFile instead of a StringIO because we don't
@@ -630,49 +630,49 @@ def _getStream(self):
 class WriteFileBase(object):
     """Convenience base class for write files which delegate to another
     stream, e.g. a file or StringIO.
-    
+
     Implement _getStream() and override any methods required.
     """
-    
+
     implements(IRawWriteFile)
-    
+
     def __init__(self, context):
         self.context = context
-        
+
         self._closed = False
         self._written = 0
-        
+
     mimeType = None
     encoding = 'utf-8'
     name = None
-    
+
     @property
     def closed(self):
         return self._closed
-    
+
     def seek(self, offset, whence=None):
         if whence is not None:
             self._getStream().seek(offset, whence)
         else:
             self._getStream().seek(offset)
-    
+
     def tell(self):
         return self._getStream().tell()
-    
+
     def close(self):
         self._closed = True
         self._getStream().close()
-    
+
     def write(self, data):
         if self._closed:
             raise ValueError("File is closed")
         self._written += len(data)
         self._getStream().write(data)
-        
+
     def writelines(self, sequence):
         for item in sequence:
             self.write(item)
-    
+
     def truncate(self, size=None):
         if self._closed:
             raise ValueError("File is closed")
@@ -681,26 +681,26 @@ def truncate(self, size=None):
         else:
             self._getStream().truncate()
         self._written = 0
-    
+
     def flush(self):
         self._getStream().flush()
-    
+
     def _getStream(self):
         raise NotImplementedError("Subclass and override this _getStream()")
 
 
 class DefaultWriteFile(object):
     """IRawWriteFile file adapter for Dexterity objects.
-    
+
     Uses RFC822 marshaler.
     """
-    
+
     implements(IRawWriteFile)
     adapts(IDexterityContent)
-    
+
     def __init__(self, context):
         self.context = context
-        
+
         self._mimeType = None
         self._encoding = 'utf-8'
         self._closed = False
@@ -708,7 +708,7 @@ def __init__(self, context):
         self._written = 0
         self._parser = FeedParser()
         self._message = None
-    
+
     @property
     def mimeType(self):
         if self._message is None:
@@ -717,56 +717,56 @@ def mimeType(self):
             return 'text/plain'
         else:
             return 'message/rfc822'
-    
+
     @mimeType.setter
     def mimeType(self, value):
         self._mimeType = value
-    
+
     @property
     def encoding(self):
         if self._message is not None:
             return self._message.get_charset() or self._encoding
         return self._encoding
-    
+
     @encoding.setter
     def encoding(self, value):
         self._encoding = value
-    
+
     @property
     def closed(self):
         return self._closed
-    
+
     @property
     def name(self):
         if self._message is not None:
             return self._message.get_filename(self._name)
         return self._name
-    
+
     @name.setter
     def name(self, value):
         self._name = value
-    
+
     def seek(self, offset, whence=None):
         raise NotImplementedError("Seeking is not supported")
-    
+
     def tell(self):
         return self._written
-    
+
     def close(self):
         self._message = self._parser.close()
         self._closed = True
         initializeObjectFromSchemata(self.context, iterSchemata(self.context), self._message, self._encoding)
-    
+
     def write(self, data):
         if self._closed:
             raise ValueError("File is closed")
         self._written += len(data)
         self._parser.feed(data)
-    
+
     def writelines(self, sequence):
         for item in sequence:
             self.write(item)
-    
+
     def truncate(self, size=None):
         if (size is None and self._written != 0) and size != 0:
             raise NotImplementedError("The 'size' argument to truncate() must be 0 - partial truncation is not supported")
@@ -774,7 +774,7 @@ def truncate(self, size=None):
             raise ValueError("File is closed")
         self._parser = FeedParser()
         self._written = 0
-    
+
     def flush(self):
         pass
 
diff --git a/plone/dexterity/fti.py b/plone/dexterity/fti.py
index 6fffe39..34b4e5e 100644
--- a/plone/dexterity/fti.py
+++ b/plone/dexterity/fti.py
@@ -38,7 +38,7 @@
 
 class DexterityFTIModificationDescription(object):
     implements(IDexterityFTIModificationDescription)
-    
+
     def __init__(self, attribute, oldValue):
         self.attribute = attribute
         self.oldValue = oldValue
@@ -47,32 +47,32 @@ def __init__(self, attribute, oldValue):
 class DexterityFTI(base.DynamicViewTypeInformation):
     """A Dexterity FTI
     """
-    
+
     implements(IDexterityFTI)
 
     meta_type = "Dexterity FTI"
-    
+
     _properties = base.DynamicViewTypeInformation._properties + (
-        { 'id': 'add_permission', 
+        { 'id': 'add_permission',
           'type': 'selection',
           'select_variable': 'possiblePermissionIds',
           'mode': 'w',
           'label': 'Add permission',
           'description': 'Permission needed to be able to add content of this type'
         },
-        { 'id': 'klass', 
+        { 'id': 'klass',
           'type': 'string',
           'mode': 'w',
           'label': 'Content type class',
           'description': 'Dotted name to the class that contains the content type'
         },
-        { 'id': 'behaviors', 
+        { 'id': 'behaviors',
           'type': 'lines',
           'mode': 'w',
           'label': 'Behaviors',
           'description': 'Named of enabled behaviors type'
         },
-        { 'id': 'schema', 
+        { 'id': 'schema',
           'type': 'string',
           'mode': 'w',
           'label': 'Schema',
@@ -80,14 +80,14 @@ class DexterityFTI(base.DynamicViewTypeInformation):
                          "This does not need to be given if model_source or model_file are given, " +
                          "and either contains an unnamed (default) schema."
         },
-        { 'id': 'model_source', 
+        { 'id': 'model_source',
           'type': 'text',
           'mode': 'w',
           'label': 'Model source',
           'description': "XML source for the type's model. Note that this takes " +
                          "precedence over any model file."
         },
-        { 'id': 'model_file', 
+        { 'id': 'model_file',
           'type': 'string',
           'mode': 'w',
           'label': 'Model file',
@@ -102,22 +102,22 @@ class DexterityFTI(base.DynamicViewTypeInformation):
         },
 
     )
-    
+
     default_aliases = {'(Default)': '(dynamic view)',
                        'view': '(selected layout)',
                        'edit': '@@edit',
                        'sharing': '@@sharing',}
-    
-    default_actions = [{'id': 'view', 
-                        'title': 'View', 
+
+    default_actions = [{'id': 'view',
+                        'title': 'View',
                         'action': 'string:${object_url}',
                         'permissions': ('View',)},
-                       {'id': 'edit', 
-                        'title': 'Edit', 
+                       {'id': 'edit',
+                        'title': 'Edit',
                         'action': 'string:${object_url}/edit',
                         'permissions': ('Modify portal content',)},
                         ]
-    
+
     immediate_view = 'view'
     default_view = 'view'
     view_methods = ('view',)
@@ -132,13 +132,13 @@ class DexterityFTI(base.DynamicViewTypeInformation):
     model_file = u""
     schema = u""
     schema_policy = u"dexterity"
-    
+
     def __init__(self, *args, **kwargs):
         super(DexterityFTI, self).__init__(*args, **kwargs)
-        
+
         if 'aliases' not in kwargs:
             self.setMethodAliases(self.default_aliases)
-            
+
         if 'actions' not in kwargs:
             for action in self.default_actions:
                 self.addAction(id=action['id'],
@@ -148,37 +148,37 @@ def __init__(self, *args, **kwargs):
                                permission=action.get('permissions', ()),
                                category=action.get('category', 'object'),
                                visible=action.get('visible', True))
-        
+
         # Default factory name to be the FTI name
         if not self.factory:
             self.factory = self.getId()
-        
+
         # In CMF (2.2+, but we've backported it) the property add_view_expr is
         # used to construct an action in the 'folder/add' category. The
         # portal_types tool loops over all FTIs and lets them provide such
         # actions.
-        # 
+        #
         # By convention, the expression is string:${folder_url}/++add++my.type
-        # 
+        #
         # The ++add++ traverser will find the FTI with name my.type, and then
         # looks up an adapter for (context, request, fti) with a name equal
         # to fti.factory, falling back on an unnamed adapter. The result is
         # assumed to be an add view.
-        # 
+        #
         # Dexterity provides a default (unnamed) adapter for any IFolderish
         # context, request and IDexterityFTI that can construct an add view
         # for any Dexterity schema.
-        
+
         if not self.add_view_expr:
             add_view_expr = kwargs.get('add_view_expr', "string:${folder_url}/++add++%s" % self.getId())
             self._setPropValue('add_view_expr', add_view_expr)
-        
+
         # Set the content_meta_type from the klass
-        
+
         klass = utils.resolveDottedName(self.klass)
         if klass is not None:
             self.content_meta_type = getattr(klass, 'meta_type', None)
-    
+
     def Title(self):
         if self.title and self.i18n_domain:
             try:
@@ -196,7 +196,7 @@ def Description(self):
                 return Message(self.description.decode('latin-1'), self.i18n_domain)
         else:
             return self.description
-    
+
     def Metatype(self):
         if self.content_meta_type:
             return self.content_meta_type
@@ -205,14 +205,14 @@ def Metatype(self):
         if klass is not None:
             self.content_meta_type = getattr(klass, 'meta_type', None)
         return self.content_meta_type
-    
+
     @property
     def hasDynamicSchema(self):
         return not(self.schema)
-    
+
     def lookupSchema(self):
         schema = None
-        
+
         # If a specific schema is given, use it
         if self.schema:
             try:
@@ -221,73 +221,73 @@ def lookupSchema(self):
                 logging.warning(u"Schema %s set for type %s cannot be resolved" % (self.schema, self.getId()))
                 # fall through to return a fake class with no
                 # fields so that end user code doesn't break
-                
+
         if schema:
             return schema
-        
+
         # Otherwise, look up a dynamic schema. This will query the model for
-        # an unnamed schema if it is the first time it is looked up. 
+        # an unnamed schema if it is the first time it is looked up.
         # See schema.py
 
         schemaName = utils.portalTypeToSchemaName(self.getId())
         return getattr(plone.dexterity.schema.generated, schemaName)
-    
+
     def lookupModel(self):
-        
+
         if self.model_source:
             return loadString(self.model_source, policy=self.schema_policy)
-        
+
         elif self.model_file:
             model_file = self._absModelFile()
             return loadFile(model_file, reload=True, policy=self.schema_policy)
-        
+
         elif self.schema:
             schema = self.lookupSchema()
             return Model({u"": schema})
-        
+
         raise ValueError("Neither model source, nor model file, nor schema is specified in FTI %s" % self.getId())
-    
+
     #
     # Base class overrides
-    # 
-    
+    #
+
     # Make sure we get an event when the FTI is modified
-    
+
     def _updateProperty(self, id, value):
         """Allow property to be updated, and fire a modified event. We do this
         on a per-property basis and invalidate selectively based on the id of
         the property that was changed.
         """
-        
+
         oldValue = getattr(self, id, None)
         super(DexterityFTI, self)._updateProperty(id, value)
         new_value = getattr(self, id, None)
-        
+
         if oldValue != new_value:
             modified(self, DexterityFTIModificationDescription(id, oldValue))
-            
+
             # Update meta_type from klass
             if id == 'klass':
                 klass = utils.resolveDottedName(new_value)
                 if klass is not None:
                     self.content_meta_type = getattr(klass, 'meta_type', None)
-    
+
     # Allow us to specify a particular add permission rather than rely on ones
     # stored in meta types that we don't have anyway
-    
+
     def isConstructionAllowed(self, container):
         if not self.add_permission:
             return False
-        
+
         permission = queryUtility(IPermission, name=self.add_permission)
         if permission is None:
             return False
-        
+
         return bool(getSecurityManager().checkPermission(permission.title, container))
-        
+
     #
     # Helper methods
-    # 
+    #
 
     def possiblePermissionIds(self):
         """Get a vocabulary of Zope 3 permission ids
@@ -300,7 +300,7 @@ def possiblePermissionIds(self):
     def _absModelFile(self):
         colons = self.model_file.count(':')
         model_file = self.model_file
-        
+
         # We have a package and not an absolute Windows path
         if colons == 1 and self.model_file[1:3] != ':\\':
             package, filename = self.model_file.split(':')
@@ -311,10 +311,10 @@ def _absModelFile(self):
         else:
             if not os.path.isabs(model_file):
                 raise ValueError(u"Model file name %s is not an absolute path and does not contain a package name in %s" % (model_file, self.getId(),))
-        
+
         if not os.path.isfile(model_file):
             raise ValueError(u"Model file %s in %s cannot be found" % (model_file, self.getId(),))
-        
+
         return model_file
 
 def _fixProperties(class_, ignored=['product', 'content_meta_type']):
@@ -323,20 +323,20 @@ def _fixProperties(class_, ignored=['product', 'content_meta_type']):
     """
     properties = []
     processed = set()
-    
+
     for item in reversed(class_._properties):
         item = item.copy()
-        
+
         if item['id'] in processed:
             continue
-        
+
         # Ignore some fields
         if item['id'] in ignored:
             continue
-        
+
         properties.append(item)
         processed.add('id')
-    
+
     class_._properties = tuple(reversed(properties))
 _fixProperties(DexterityFTI)
 
@@ -344,7 +344,7 @@ def _fixProperties(class_, ignored=['product', 'content_meta_type']):
 
 def register(fti):
     """Helper method to:
-    
+
          - register an FTI as a local utility
          - register a local factory utility
          - register an add view
@@ -353,20 +353,20 @@ def register(fti):
     fti = aq_base(fti) # remove acquisition wrapper
     site = getUtility(ISiteRoot)
     site_manager = getSiteManager(site)
-    
+
     portal_type = fti.getId()
-    
+
     fti_utility = queryUtility(IDexterityFTI, name=portal_type)
     if fti_utility is None:
         site_manager.registerUtility(fti, IDexterityFTI, portal_type, info='plone.dexterity.dynamic')
-        
+
     factory_utility = queryUtility(IFactory, name=fti.factory)
     if factory_utility is None:
         site_manager.registerUtility(DexterityFactory(portal_type), IFactory, fti.factory, info='plone.dexterity.dynamic')
 
 def unregister(fti, old_name=None):
     """Helper method to:
-    
+
         - unregister the FTI local utility
         - unregister any local factory utility associated with the FTI
         - unregister any local add view associated with the FTI
@@ -374,15 +374,15 @@ def unregister(fti, old_name=None):
     site = queryUtility(ISiteRoot)
     if site is None:
         return
-    
+
     site_manager = getSiteManager(site)
-    
+
     portal_type = old_name or fti.getId()
 
     notify(SchemaInvalidatedEvent(portal_type))
-    
+
     site_manager.unregisterUtility(provided=IDexterityFTI, name=portal_type)
-    unregister_factory(fti.factory, site_manager)    
+    unregister_factory(fti.factory, site_manager)
 
 def unregister_factory(factory_name, site_manager):
     """Helper method to unregister factories when unused by any dexterity
@@ -393,7 +393,7 @@ def unregister_factory(factory_name, site_manager):
     if factory_name in [f.component.factory for f in utilities
                         if (f.provided, f.info) == (IDexterityFTI, 'plone.dexterity.dynamic')]:
         return
-    
+
     # If a factory with a matching name exists, remove it
     if [f for f in utilities
         if (f.provided, f.name, f.info) == (IFactory, factory_name, 'plone.dexterity.dynamic')]:
@@ -402,78 +402,78 @@ def unregister_factory(factory_name, site_manager):
 def ftiAdded(object, event):
     """When the FTI is created, install local components
     """
-    
+
     if not IDexterityFTI.providedBy(event.object):
         return
-    
+
     register(event.object)
-    
+
 def ftiRemoved(object, event):
     """When the FTI is removed, uninstall local coponents
     """
-    
+
     if not IDexterityFTI.providedBy(event.object):
         return
-            
+
     unregister(event.object)
 
 def ftiRenamed(object, event):
     """When the FTI is modified, ensure local components are still valid
     """
-    
+
     if not IDexterityFTI.providedBy(event.object):
         return
-    
+
     if event.oldParent is None or event.newParent is None or event.oldName == event.newName:
         return
-    
+
     unregister(event.object, event.oldName)
     register(event.object)
 
 def ftiModified(object, event):
-    """When an FTI is modified, re-sync and invalidate the schema, if 
+    """When an FTI is modified, re-sync and invalidate the schema, if
     necessary.
     """
-    
+
     if not IDexterityFTI.providedBy(event.object):
         return
-    
+
     fti = event.object
     portal_type = fti.getId()
-    
+
     mod = {}
     for desc in event.descriptions:
         if IDexterityFTIModificationDescription.providedBy(desc):
             mod[desc.attribute] = desc.oldValue
-    
-    # If the factory utility name was modified, we may get an orphan if one 
+
+    # If the factory utility name was modified, we may get an orphan if one
     # was registered as a local utility to begin with. If so, remove the
     # orphan.
-    
+
     if 'factory' in mod:
         old_factory = mod['factory']
-        
+
         site = getUtility(ISiteRoot)
         site_manager = getSiteManager(site)
-        
+
         # Remove previously registered factory, if no other type uses it.
         unregister_factory(old_factory, site_manager)
-        
+
         # Register a new local factory if one doesn't exist already
         new_factory_utility = queryUtility(IFactory, name=fti.factory)
         if new_factory_utility is None:
             site_manager.registerUtility(DexterityFactory(portal_type), IFactory, fti.factory, info='plone.dexterity.dynamic')
-        
+
     # Determine if we need to invalidate the schema at all
     if 'behaviors' in mod or 'schema' in mod or 'model_source' in mod or 'model_file' in mod:
-        
+
         # Determine if we need to re-sync a dynamic schema
         if (fti.model_source or fti.model_file) and ('model_source' in mod or 'model_file' in mod):
-            
+
             schemaName = utils.portalTypeToSchemaName(portal_type)
             schema = getattr(plone.dexterity.schema.generated, schemaName)
-    
+
             model = fti.lookupModel()
             syncSchema(model.schema, schema, overwrite=True)
-        
+
         notify(SchemaInvalidatedEvent(portal_type))
diff --git a/plone/dexterity/interfaces.py b/plone/dexterity/interfaces.py
index 60b85c3..20b2609 100644
--- a/plone/dexterity/interfaces.py
+++ b/plone/dexterity/interfaces.py
@@ -24,7 +24,7 @@ class IDexterityFTI(ITypeInformation):
     def lookupSchema():
         """Return an InterfaceClass that represents the schema of this type.
         Raises a ValueError if it cannot be found.
-        
+
         If a schema interface is specified, return this. Otherwise, look up
         the model from either the TTW model source string or a specified
         model XML file, and build a schema from the unnamed schema
@@ -35,19 +35,19 @@ def lookupModel():
         """Return the IModel specified in either the model_source or
         model_file (the former takes precedence). See plone.supermodel for
         more information about this type.
-        
+
         If neither a model_source or a model_file is given, but a schema is
         given, return a faux model that contains just this schema.
-        
+
         Note that model.schema is not necessarily going to be the same as
         the schema returned by lookupSchema().
         """
-    
+
     add_permission = zope.schema.DottedName(
             title=u"Add permission",
             description=u"Zope 3 permission name for the permission required to construct this content",
         )
-    
+
     behaviors = zope.schema.List(
             title=u"Behaviors",
             description=u"A list of behaviors that are enabled for this type. "
@@ -70,11 +70,11 @@ def lookupModel():
 
     model_file = zope.schema.Text(
             title=u"Model file",
-            description=u"A file that contains an XML model. " 
-                        u"This may be an absolute path, or one relative to a " 
+            description=u"A file that contains an XML model. "
+                        u"This may be an absolute path, or one relative to a "
                         u"package, e.g. my.package:model.xml"
         )
-    
+
     hasDynamicSchema = zope.schema.Bool(
             title=u"Whether or not the FTI uses a dynamic schema.",
             readonly=True
@@ -83,19 +83,19 @@ def lookupModel():
 class IDexterityFTIModificationDescription(IModificationDescription):
     """Descriptor passed with an IObjectModifiedEvent for a Dexterity FTI.
     """
-    
+
     attribute = zope.schema.ASCII(title=u"Name of the attribute that was modified")
     oldValue = Attribute("Old value")
 
 class IDexterityFactory(IFactory):
     """A factory that can create Dexterity objects.
-    
+
     This factory will create an object by looking up the klass property of
-    the FTI with the given portal type. It will also set the portal_type 
+    the FTI with the given portal type. It will also set the portal_type
     on the instance and mark the instance as providing the schema interface
     if it does not do so already.
     """
-    
+
     portal_type = zope.schema.TextLine(title=u"Portal type name",
                                        description=u"The portal type this is an FTI for")
 
@@ -109,11 +109,11 @@ class IDexteritySchema(Interface):
 
 class ISchemaInvalidatedEvent(Interface):
     """Event fired when the schema cache should be invalidated.
-    
+
     If the portal_type is not given, all schemata will be cleared from the
     cache.
     """
-    
+
     portal_type = zope.schema.TextLine(title=u"FTI name", required=False)
 
 # Content
@@ -125,7 +125,7 @@ class IDexterityContent(Interface):
 class IDexterityItem(IDexterityContent):
     """Marker interface applied to dexterity-managed non-folderish objects
     """
-    
+
 class IDexterityContainer(IDexterityContent):
     """Marker interface applied to dexterity-managed folderish objects
     """
diff --git a/plone/dexterity/meta.zcml b/plone/dexterity/meta.zcml
index 79876ba..94ffb10 100644
--- a/plone/dexterity/meta.zcml
+++ b/plone/dexterity/meta.zcml
@@ -4,5 +4,5 @@
 
     <!-- Include ZCML directive from plone.behavior -->
     <include package="plone.behavior" file="meta.zcml" />
-    
+
 </configure>
diff --git a/plone/dexterity/schema.py b/plone/dexterity/schema.py
index 5188299..2ddd0a7 100644
--- a/plone/dexterity/schema.py
+++ b/plone/dexterity/schema.py
@@ -57,28 +57,28 @@ def decorator(self, portal_type):
 
 
 class SchemaCache(object):
-    """Simple schema cache. 
-    
+    """Simple schema cache.
+
     This cache will store a Python object reference to the schema, as returned
     by fti.lookupSchema(), for any number of portal types. The value will
     be cached until the server is restarted or the cache is invalidated or
     cleared.
-    
+
     You should only use this if you require bare-metal speed. For almost all
     operations, it's safer and easier to do:
-    
+
         >>> fti = getUtility(IDexterityFTI, name=portal_type)
         >>> schema = fti.lookupSchema()
-    
+
     The lookupSchema() call is probably as fast as this cache. However, if
     you need to avoid the utility lookup, you can use the cache like so:
-    
+
         >>> from plone.dexterity.schema import SCHEMA_CACHE
         >>> my_schema = SCHEMA_CACHE.get(portal_type)
-        
+
     The cache uses the FTI's modification time as its invariant.
     """
-    
+
     lock = RLock()
 
     def __init__(self, cache_enabled=True):
@@ -123,7 +123,7 @@ def invalidate(self, portal_type):
 
 class SchemaInvalidatedEvent(object):
     implements(ISchemaInvalidatedEvent)
-    
+
     def __init__(self, portal_type):
         self.portal_type = portal_type
 
@@ -139,62 +139,62 @@ def invalidate_schema(event):
 class SchemaModuleFactory(object):
     """Create dynamic schema interfaces on the fly
     """
-    
+
     implements(IDynamicObjectFactory)
-    
+
     lock = RLock()
     _transient_SCHEMA_CACHE = {}
-    
+
     @synchronized(lock)
     def __call__(self, name, module):
         """Someone tried to load a dynamic interface that has not yet been
         created yet. We will attempt to load it from the FTI if we can. If
         the FTI doesn't exist, create a temporary marker interface that we
         can fill later.
-        
-        The goal here is to ensure that we create exactly one interface 
+
+        The goal here is to ensure that we create exactly one interface
         instance for each name. If we can't find an FTI, we'll cache the
         interface so that we don't get a new one with a different id later.
         This cache is global, so we synchronise the method with a thread
         lock.
-        
+
         Once we have a properly populated interface, we set it onto the
         module using setattr(). This means that the factory will not be
         invoked again.
         """
-        
+
         try:
             prefix, portal_type, schemaName = utils.splitSchemaName(name)
         except ValueError:
             return None
-        
+
         if name in self._transient_SCHEMA_CACHE:
             schema = self._transient_SCHEMA_CACHE[name]
         else:
             bases = ()
-            
+
             is_default_schema = not schemaName
             if is_default_schema:
                 bases += (IDexteritySchema,)
-        
+
             schema = InterfaceClass(name, bases, __module__=module.__name__)
-        
+
             if is_default_schema:
                 alsoProvides(schema, IContentType)
-        
+
         fti = queryUtility(IDexterityFTI, name=portal_type)
         if fti is None and name not in self._transient_SCHEMA_CACHE:
             self._transient_SCHEMA_CACHE[name] = schema
         elif fti is not None:
-            model = fti.lookupModel()            
+            model = fti.lookupModel()
             syncSchema(model.schemata[schemaName], schema, sync_bases=True)
 
             # Save this schema in the module - this factory will not be
             # called again for this name
-            
+
             if name in self._transient_SCHEMA_CACHE:
                 del self._transient_SCHEMA_CACHE[name]
-                
+
             setattr(module, name, schema)
 
         return schema
@@ -206,13 +206,13 @@ class DexteritySchemaPolicy(object):
     in code.
     """
     implements(ISchemaPolicy)
-    
+
     def module(self, schemaName, tree):
         return 'plone.dexterity.schema.transient'
-        
+
     def bases(self, schemaName, tree):
         return ()
-        
+
     def name(self, schemaName, tree):
         # We use a temporary name whilst the interface is being generated;
         # when it's first used, we know the portal_type and site, and can
diff --git a/plone/dexterity/tests/schemata.py b/plone/dexterity/tests/schemata.py
index 8df573a..e9f095d 100644
--- a/plone/dexterity/tests/schemata.py
+++ b/plone/dexterity/tests/schemata.py
@@ -6,17 +6,17 @@
 class ITestSchema(Interface):
     """Schema used for testing
     """
-    
+
     title = schema.TextLine(title=u"Title",
                             description=u"Administrative title")
-                        
+
     description = schema.Text(title=u"Description",
                               required=False)
 
 class ITaggedValueSchema(Interface):
     """Schema used for testing tagged value filenames
     """
-    
+
 ITaggedValueSchema.setTaggedValue(FILENAME_KEY, '/path/to/dummy.xml')
 
 class IDerivedFromTaggedValueSchema(ITaggedValueSchema):
diff --git a/plone/dexterity/tests/test_content_integration.py b/plone/dexterity/tests/test_content_integration.py
index d02f640..bdd04bf 100644
--- a/plone/dexterity/tests/test_content_integration.py
+++ b/plone/dexterity/tests/test_content_integration.py
@@ -7,9 +7,9 @@
 
 
 class TestUUIDIntegration(unittest.TestCase):
-    
+
     layer = UNIT_TESTING
-    
+
     def setUp(self):
         import zope.component.testing
         import plone.uuid
@@ -18,7 +18,7 @@ def setUp(self):
 
         zope.component.testing.setUp()
         xmlconfig.file('configure.zcml', plone.uuid)
-    
+
     def test_uuid_assigned_on_creation(self):
         from plone.dexterity.content import Item
         from plone.uuid.interfaces import IUUID
diff --git a/plone/dexterity/tests/test_primary.py b/plone/dexterity/tests/test_primary.py
index 29228bb..5083d7e 100644
--- a/plone/dexterity/tests/test_primary.py
+++ b/plone/dexterity/tests/test_primary.py
@@ -21,7 +21,7 @@ class ITest(Interface):
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITest).count(0, None)
         self.expect(fti_mock.behaviors).result([]).count(0, None)
-        self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")        
+        self.mock_utility(fti_mock, IDexterityFTI, name=u"testtype")
         self.replay()
 
         item = Item('item')
diff --git a/plone/dexterity/tests/test_security.py b/plone/dexterity/tests/test_security.py
index 14a8c54..7751b93 100644
--- a/plone/dexterity/tests/test_security.py
+++ b/plone/dexterity/tests/test_security.py
@@ -26,12 +26,12 @@ def tearDown(self):
         SCHEMA_CACHE.cache_enabled = True
 
     def test_item(self):
-        
+
         # Mock schema model
         class ITestSchema(Interface):
             test = zope.schema.TextLine(title=u"Test")
         ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View'))
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITestSchema)
@@ -49,9 +49,9 @@ class ITestSchema(Interface):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         # Check permission
-        
+
         securityManager_mock = self.mocker.mock()
         self.expect(securityManager_mock.checkPermission("View", item)).result(False)
         self.expect(securityManager_mock.checkPermission("View foo", item)).result(True)
@@ -59,20 +59,20 @@ class ITestSchema(Interface):
         self.expect(getSecurityManager_mock()).result(securityManager_mock).count(2)
 
         self.mocker.replay()
-        
+
         self.assertFalse(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
-        
+
         # Unknown attributes are allowed
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_container(self):
-        
+
         # Mock schema model
         class ITestSchema(Interface):
             test = zope.schema.TextLine(title=u"Test")
         ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View'))
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITestSchema)
@@ -90,7 +90,7 @@ class ITestSchema(Interface):
         container.portal_type = u"testtype"
         container.test = u"foo"
         container.foo = u"bar"
-        
+
         # Check permission
         securityManager_mock = self.mocker.mock()
         self.expect(securityManager_mock.checkPermission("View", container)).result(False)
@@ -99,23 +99,23 @@ class ITestSchema(Interface):
         self.expect(getSecurityManager_mock()).result(securityManager_mock).count(2)
 
         self.mocker.replay()
-        
+
         self.assertFalse(container.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(container.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
-        
+
         # Unknown attributes are allowed
         self.assertTrue(container.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_subclass(self):
-        
+
         # Mock schema model
         class ITestSchema(Interface):
             test = zope.schema.TextLine(title=u"Test")
         ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View'))
-        
+
         class Foo(Item):
             pass
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITestSchema)
@@ -133,7 +133,7 @@ class Foo(Item):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         # Check permission
         securityManager_mock = self.mocker.mock()
         self.expect(securityManager_mock.checkPermission("View", item)).result(False)
@@ -142,19 +142,19 @@ class Foo(Item):
         self.expect(getSecurityManager_mock()).result(securityManager_mock).count(2)
 
         self.mocker.replay()
-        
+
         self.assertFalse(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
-        
+
         # Unknown attributes are allowed
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_no_tagged_value(self):
-        
+
         # Mock schema model
         class ITestSchema(Interface):
             test = zope.schema.TextLine(title=u"Test")
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITestSchema)
@@ -168,23 +168,23 @@ class ITestSchema(Interface):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         self.mocker.replay()
-        
+
         # Everything allowed
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
-        
+
         # Unknown attributes are allowed
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_no_read_permission(self):
-        
+
         # Mock schema model
         class ITestSchema(Interface):
             test = zope.schema.TextLine(title=u"Test")
         ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(foo='foo.View'))
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(ITestSchema)
@@ -201,7 +201,7 @@ class ITestSchema(Interface):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         # Check permission
         securityManager_mock = self.mocker.mock()
         self.expect(securityManager_mock.checkPermission("View foo", item)).result(True)
@@ -209,15 +209,15 @@ class ITestSchema(Interface):
         self.expect(getSecurityManager_mock()).result(securityManager_mock).count(1)
 
         self.mocker.replay()
-        
+
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
-        
+
         # Unknown attributes are allowed
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_no_schema(self):
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).result(None).count(3) # not cached this time
@@ -229,18 +229,18 @@ def test_no_schema(self):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         self.mocker.replay()
-        
+
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_schema_exception(self):
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
-        
+
         self.expect(fti_mock.lookupSchema()).count(3).throw(AttributeError)
 
         self.mock_utility(fti_mock, IDexterityFTI, u'testtype')
@@ -250,15 +250,15 @@ def test_schema_exception(self):
         item.portal_type = u"testtype"
         item.test = u"foo"
         item.foo = u"bar"
-        
+
         self.mocker.replay()
-        
+
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('test', u"foo"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('foo', u"bar"))
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('random', u"stuff"))
 
     def test_empty_name(self):
-        
+
         # Mock FTI
         fti_mock = self.mocker.mock(DexterityFTI)
         self.expect(fti_mock.lookupSchema()).count(0)
@@ -267,9 +267,9 @@ def test_empty_name(self):
         # Content item
         item = Item('test')
         item.portal_type = u"testtype"
-        
+
         self.mocker.replay()
-        
+
         self.assertTrue(item.__allow_access_to_unprotected_subobjects__('', u"foo"))
 
 def test_suite():




-------------------------------------------------------------------------------
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CHANGES.log
Type: application/octet-stream
Size: 95362 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140823/9a9fe47d/attachment-0002.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: build.log
Type: application/octet-stream
Size: 84160 bytes
Desc: not available
URL: <http://lists.plone.org/pipermail/plone-testbot/attachments/20140823/9a9fe47d/attachment-0003.obj>


More information about the Testbot mailing list