[Testbot] Plone 5.0 - Python 2.7 - Build # 1896 - Regression! - 2 failure(s)

jenkins at plone.org jenkins at plone.org
Mon Mar 10 03:19:09 UTC 2014


-------------------------------------------------------------------------------
Plone 5.0 - Python 2.7 - Build # 1896 - Failure!
-------------------------------------------------------------------------------

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


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

Repository: plone.app.portlets
Branch: refs/heads/master
Date: 2014-03-09T09:13:00-07:00
Author: Bo Simonsen (bosim) <bo at geekworld.dk>
Commit: https://github.com/plone/plone.app.portlets/commit/fc1581421a745aa0c2b0b7976c1f3b539ce1d904

Use z3c.form for portlet forms.

Files changed:
M CHANGES.rst
M plone/app/portlets/browser/configure.zcml
M plone/app/portlets/browser/formhelper.py
M plone/app/portlets/metaconfigure.py
M plone/app/portlets/portlets/actions.py
M plone/app/portlets/portlets/base.py
M plone/app/portlets/portlets/classic.py
M plone/app/portlets/portlets/language.py
M plone/app/portlets/portlets/login.py
M plone/app/portlets/portlets/navigation.py
M plone/app/portlets/portlets/news.py
M plone/app/portlets/portlets/recent.py
M plone/app/portlets/portlets/review.py
M plone/app/portlets/portlets/rss.py
M plone/app/portlets/portlets/search.py
M plone/app/portlets/tests/test_configuration.py
M plone/app/portlets/tests/test_navigation_portlet.py
M setup.py
D plone/app/portlets/browser/z3cformhelper.py
D plone/app/portlets/tests/profiles/z3ctesting/portlets.xml
D plone/app/portlets/tests/test_z3cforms.py

diff --git a/CHANGES.rst b/CHANGES.rst
index f0f5354..42638fe 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,10 +1,14 @@
 Changelog
 =========
 
-2.5.1 (unreleased)
-------------------
+3.0 (unreleased)
+----------------
 
-- Nothing changed yet.
+- Use z3c.form for portlet forms.
+  [bosim, davisagli]
+
+- Store navigation portlet root setting as a UID rather than a path.
+  [davisagli]
 
 
 2.5.0 (2014-03-02)
diff --git a/plone/app/portlets/browser/configure.zcml b/plone/app/portlets/browser/configure.zcml
index 3f88648..9836909 100644
--- a/plone/app/portlets/browser/configure.zcml
+++ b/plone/app/portlets/browser/configure.zcml
@@ -213,14 +213,6 @@
 
     </configure>
 
-    <!-- Default page layout for portlet add/edit forms -->
-    <adapter
-      for=".interfaces.IPortletForm"
-      factory=".formhelper.portlets_named_template_adapter"
-      name="default"
-      provides="zope.formlib.namedtemplate.INamedTemplate"
-      />
-
     <!-- Resources -->
     <browser:resource
         name="manage-portlets.js"
diff --git a/plone/app/portlets/browser/formhelper.py b/plone/app/portlets/browser/formhelper.py
index f92a35d..e8579c6 100644
--- a/plone/app/portlets/browser/formhelper.py
+++ b/plone/app/portlets/browser/formhelper.py
@@ -1,31 +1,26 @@
-from five.formlib import formbase
-from zope.interface import implements
+from z3c.form import button
+from z3c.form import form
 from zope.component import getMultiAdapter
-from zope.formlib import form
-
+from zope.interface import implements
 import zope.event
 import zope.lifecycleevent
 
-from Acquisition import aq_parent, aq_inner
 from Products.Five.browser import BrowserView
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 
-from plone.app.form import named_template_adapter
-from plone.app.form.interfaces import IPlonePageForm
-from plone.app.form.validators import null_validator
+from Acquisition import aq_parent, aq_inner, aq_base
+from Acquisition.interfaces import IAcquirer
 
 from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.interfaces import IPortletPermissionChecker
 from plone.app.portlets.browser.interfaces import IPortletAddForm
 from plone.app.portlets.browser.interfaces import IPortletEditForm
+from plone.app.portlets.interfaces import IPortletPermissionChecker
+from plone.autoform.form import AutoExtensibleForm
 
-# Add a named template form, which allows us to carry some extra information
-# about the referer
-_template = ViewPageTemplateFile('templates/portlets-pageform.pt')
-portlets_named_template_adapter = named_template_adapter(_template)
+from Products.statusmessages.interfaces import IStatusMessage
 
 
-class AddForm(formbase.AddFormBase):
+class AddForm(AutoExtensibleForm, form.AddForm):
     """A base add form for portlets.
 
     Use this for portlet assignments that require configuration before being
@@ -45,38 +40,70 @@ def create(self):
             return MyAssignment()
     """
 
-    implements(IPortletAddForm, IPlonePageForm)
+    implements(IPortletAddForm)
+
+    template = ViewPageTemplateFile('templates/z3cform-portlets-pageform.pt')
+
+    label = _(u"Configure portlet")
 
-    form_name = _(u"Configure portlet")
+    def add(self, object):
+        ob = self.context.add(object)
+        self._finishedAdd = True
+        return ob
 
     def __call__(self):
+        self.request.set('disable_border', 1)
+        self.request.set('disable_plone.leftcolumn', 1)
+        self.request.set('disable_plone.rightcolumn', 1)
         IPortletPermissionChecker(aq_parent(aq_inner(self.context)))()
         return super(AddForm, self).__call__()
 
+    def createAndAdd(self, data):
+        obj = self.create(data)
+
+        # Acquisition wrap temporarily to satisfy things like vocabularies
+        # depending on tools
+        container = aq_inner(self.context)
+
+        if IAcquirer.providedBy(obj):
+            obj = obj.__of__(container)
+        form.applyChanges(self, obj, data)
+        obj = aq_base(obj)
+
+        zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(obj))
+        self.add(obj)
+        return obj
+
+    @property
     def referer(self):
         return self.request.get('referer', '')
 
     def nextURL(self):
-        referer = self.request.form.get('referer')
-        if referer:
-            return referer
-        else:
-            addview = aq_parent(aq_inner(self.context))
-            context = aq_parent(aq_inner(addview))
-            url = str(getMultiAdapter((context, self.request), name=u"absolute_url"))
-            return url + '/@@manage-portlets'
-
-    @form.action(_(u"label_save", default=u"Save"), name=u'save')
-    def handle_save_action(self, action, data):
-        self.createAndAdd(data)
-
-    @form.action(_(u"label_cancel", default=u"Cancel"),
-                 validator=null_validator,
-                 name=u'cancel')
-    def handle_cancel_action(self, action, data):
+        if self.referer:
+            return self.referer
+        addview = aq_parent(aq_inner(self.context))
+        context = aq_parent(aq_inner(addview))
+        url = str(getMultiAdapter((context, self.request),
+                                  name=u"absolute_url"))
+        return url + '/@@manage-portlets'
+
+    @button.buttonAndHandler(_(u"label_save", default=u"Save"), name='add')
+    def handleAdd(self, action):
+        data, errors = self.extractData()
+        if errors:
+            self.status = self.formErrorsMessage
+            return
+        obj = self.createAndAdd(data)
+        if obj is not None:
+            # mark only as finished if we get the new object
+            self._finishedAdd = True
+
+    @button.buttonAndHandler(_(u"label_cancel", default=u"Cancel"),
+                             name='cancel_add')
+    def handleCancel(self, action):
         nextURL = self.nextURL()
         if nextURL:
-            self.request.response.redirect(self.nextURL())
+            self.request.response.redirect(nextURL)
         return ''
 
 
@@ -106,58 +133,69 @@ def nextURL(self):
         else:
             addview = aq_parent(aq_inner(self.context))
             context = aq_parent(aq_inner(addview))
-            url = str(getMultiAdapter((context, self.request), name=u"absolute_url"))
+            url = str(getMultiAdapter((context, self.request),
+                                      name=u"absolute_url"))
             return url + '/@@manage-portlets'
 
     def create(self):
         raise NotImplementedError("concrete classes must implement create()")
 
 
-class EditForm(formbase.EditFormBase):
+class EditForm(AutoExtensibleForm, form.EditForm):
     """An edit form for portlets.
     """
 
-    implements(IPortletEditForm, IPlonePageForm)
+    implements(IPortletEditForm)
+
+    template = ViewPageTemplateFile('templates/z3cform-portlets-pageform.pt')
 
-    form_name = _(u"Modify portlet")
+    label = _(u"Modify portlet")
 
     def __call__(self):
+        self.request.set('disable_border', 1)
+        self.request.set('disable_plone.leftcolumn', 1)
+        self.request.set('disable_plone.rightcolumn', 1)
         IPortletPermissionChecker(aq_parent(aq_inner(self.context)))()
         return super(EditForm, self).__call__()
 
+    @property
     def referer(self):
         return self.request.get('referer', '')
 
     def nextURL(self):
-        referer = self.request.form.get('referer')
-        if referer:
-            return referer
-        else:
-            portlet = aq_inner(self.context)
-            context = aq_parent(portlet)
-            url = str(getMultiAdapter((context, self.request), name=u"absolute_url"))
-            return url + '/@@manage-portlets'
-
-    @form.action(_(u"label_save", default=u"Save"),
-                 condition=form.haveInputWidgets,
-                 name=u'save')
-    def handle_save_action(self, action, data):
-        if form.applyChanges(self.context, self.form_fields, data, self.adapters):
-            zope.event.notify(zope.lifecycleevent.ObjectModifiedEvent(self.context))
+        if self.referer:
+            return self.referer
+        editview = aq_parent(aq_inner(self.context))
+        context = aq_parent(aq_inner(editview))
+        url = str(getMultiAdapter((context, self.request),
+                                  name=u"absolute_url"))
+        return url + '/@@manage-portlets'
+
+    @button.buttonAndHandler(_(u"label_save", default=u"Save"), name='apply')
+    def handleSave(self, action):
+        data, errors = self.extractData()
+        if errors:
+            self.status = self.formErrorsMessage
+            return
+        changes = self.applyChanges(data)
+        if changes:
             self.status = "Changes saved"
+            IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
+                                                          "info")
         else:
             self.status = "No changes"
+            IStatusMessage(self.request).addStatusMessage(_(u"No changes"),
+                                                          "info")
 
         nextURL = self.nextURL()
         if nextURL:
             self.request.response.redirect(self.nextURL())
         return ''
 
-    @form.action(_(u"label_cancel", default=u"Cancel"),
-                 validator=null_validator,
-                 name=u'cancel')
-    def handle_cancel_action(self, action, data):
+    @button.buttonAndHandler(_(u"label_cancel", default=u"Cancel"),
+                             name='cancel_add')
+    def handleCancel(self, action):
         nextURL = self.nextURL()
         if nextURL:
-            self.request.response.redirect(self.nextURL())
+            self.request.response.redirect(nextURL)
         return ''
diff --git a/plone/app/portlets/browser/z3cformhelper.py b/plone/app/portlets/browser/z3cformhelper.py
deleted file mode 100644
index e2a1944..0000000
--- a/plone/app/portlets/browser/z3cformhelper.py
+++ /dev/null
@@ -1,145 +0,0 @@
-from z3c.form import button
-from z3c.form import form
-from zope.component import getMultiAdapter
-from zope.interface import implements
-import zope.event
-import zope.lifecycleevent
-
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from Acquisition import aq_parent, aq_inner, aq_base
-from Acquisition.interfaces import IAcquirer
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.browser.interfaces import IPortletAddForm
-from plone.app.portlets.browser.interfaces import IPortletEditForm
-from plone.app.portlets.interfaces import IPortletPermissionChecker
-
-from Products.statusmessages.interfaces import IStatusMessage
-
-class AddForm(form.AddForm):
-    implements(IPortletAddForm)
-
-    template = ViewPageTemplateFile('templates/z3cform-portlets-pageform.pt')
-    
-    label = _(u"Configure portlet")
-
-    def add(self, object):
-        ob = self.context.add(object)
-        self._finishedAdd = True
-        return ob
-
-    def __call__(self):
-        self.request.set('disable_border', 1)
-        self.request.set('disable_plone.leftcolumn', 1)
-        self.request.set('disable_plone.rightcolumn', 1)
-        IPortletPermissionChecker(aq_parent(aq_inner(self.context)))()
-        return super(AddForm, self).__call__()
-
-    def createAndAdd(self, data):
-        obj = self.create(data)
-
-        # Acquisition wrap temporarily to satisfy things like vocabularies
-        # depending on tools
-        container = aq_inner(self.context)
-
-        if IAcquirer.providedBy(obj):
-            obj = obj.__of__(container)
-        form.applyChanges(self, obj, data)
-        obj = aq_base(obj)
-
-        zope.event.notify(zope.lifecycleevent.ObjectCreatedEvent(obj))
-        self.add(obj)
-        return obj
-
-    @property
-    def referer(self):
-        return self.request.get('referer', '')
-    
-    def nextURL(self):
-        if self.referer:
-            return self.referer
-        addview = aq_parent(aq_inner(self.context))
-        context = aq_parent(aq_inner(addview))
-        url = str(getMultiAdapter((context, self.request),
-                                  name=u"absolute_url"))
-        return url + '/@@manage-portlets'
-
-    @button.buttonAndHandler(_(u"label_save", default=u"Save"), name='add')
-    def handleAdd(self, action):
-        data, errors = self.extractData()
-        if errors:
-            self.status = self.formErrorsMessage
-            return
-        obj = self.createAndAdd(data)
-        if obj is not None:
-            # mark only as finished if we get the new object
-            self._finishedAdd = True
-
-    @button.buttonAndHandler(_(u"label_cancel", default=u"Cancel"),
-                             name='cancel_add')
-    def handleCancel(self, action):
-        nextURL = self.nextURL()
-        if nextURL:
-            self.request.response.redirect(nextURL)
-        return ''
-
-
-class EditForm(form.EditForm):
-    """An edit form for portlets.
-    """
-
-    implements(IPortletEditForm)
-
-    template = ViewPageTemplateFile('templates/z3cform-portlets-pageform.pt')
-    
-    label = _(u"Modify portlet")
-
-    def __call__(self):
-        self.request.set('disable_border', 1)
-        self.request.set('disable_plone.leftcolumn', 1)
-        self.request.set('disable_plone.rightcolumn', 1)
-        IPortletPermissionChecker(aq_parent(aq_inner(self.context)))()
-        return super(EditForm, self).__call__()
-
-    @property
-    def referer(self):
-        return self.request.get('referer', '')
-
-    def nextURL(self):
-        if self.referer:
-            return self.referer
-        editview = aq_parent(aq_inner(self.context))
-        context = aq_parent(aq_inner(editview))
-        url = str(getMultiAdapter((context, self.request),
-                                  name=u"absolute_url"))
-        return url + '/@@manage-portlets'
-
-    @button.buttonAndHandler(_(u"label_save", default=u"Save"), name='apply')
-    def handleSave(self, action):
-        data, errors = self.extractData()
-        if errors:
-            self.status = self.formErrorsMessage
-            return
-        changes = self.applyChanges(data)
-        if changes:
-            self.status = "Changes saved"
-            IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
-                                                          "info")
-        else:
-            self.status = "No changes"
-            IStatusMessage(self.request).addStatusMessage(_(u"No changes"),
-                                                          "info")
-
-        nextURL = self.nextURL()
-        if nextURL:
-            self.request.response.redirect(self.nextURL())
-        return ''
-
-    @button.buttonAndHandler(_(u"label_cancel", default=u"Cancel"),
-                             name='cancel_add')
-    def handleCancel(self, action):
-        nextURL = self.nextURL()
-        if nextURL:
-            self.request.response.redirect(nextURL)
-        return ''
diff --git a/plone/app/portlets/metaconfigure.py b/plone/app/portlets/metaconfigure.py
index 1a4bec6..a9fca98 100644
--- a/plone/app/portlets/metaconfigure.py
+++ b/plone/app/portlets/metaconfigure.py
@@ -29,8 +29,8 @@ def portletDirective(_context, name, interface, assignment, renderer, addview,
 
     Portlets that consist of a simple assignment class deriving form
     base.Assignment, a renderer deriving from base.Renderer, an addview
-    using formlib and deriving from base.AddForm and an editview (optional)
-    using formlib and deriving from base.EditForm, can use this directive
+    using z3c form and deriving from base.AddForm and an editview (optional)
+    using z3c form and deriving from base.EditForm, can use this directive
     to avoid having to regiter each of those components individually.
 
     In addition, we register the portlet interface using IPortletTypeInterface
diff --git a/plone/app/portlets/portlets/actions.py b/plone/app/portlets/portlets/actions.py
index f7cf4d5..44aac34 100644
--- a/plone/app/portlets/portlets/actions.py
+++ b/plone/app/portlets/portlets/actions.py
@@ -1,15 +1,13 @@
 # -*- coding: utf-8 -*-
 from Acquisition import aq_inner
-from zope.interface import implements
-from zope import schema
-from zope.formlib import form
-from zope.component import getMultiAdapter
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-from plone.portlets.interfaces import IPortletDataProvider
+from plone.app.portlets import PloneMessageFactory as _
 from plone.app.portlets.portlets import base
 from plone.memoize import view as pm_view
-
-from plone.app.portlets import PloneMessageFactory as _
+from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope import schema
+from zope.component import getMultiAdapter
+from zope.interface import implements
 
 
 class IActionsPortlet(IPortletDataProvider):
@@ -96,7 +94,6 @@ def available(self):
         """Override base class"""
         return bool(self.actionLinks())
 
-
     @property
     def title(self):
         """Portlet title"""
@@ -121,7 +118,7 @@ def cachedLinks(self, actions_category, default_icon, show_icons):
         try:
             actions = context_state.actions(actions_category)
             HAS_PLONE4 = True
-        except TypeError: # Plone < 4
+        except TypeError:  # Plone < 4
            actions = context_state.actions()
 
         # Finding method for icons
@@ -146,7 +143,7 @@ def render_icon(category, action_id, default):
         # Building the result as list of dicts
         result = []
 
-        if actions_category=="portal_tabs":
+        if actions_category == "portal_tabs":
             # Special case for portal_tabs (we rely on content in Plone root)
             portal_tabs_view = getMultiAdapter(
                 (self.context, self.context.REQUEST), name='portal_tabs_view')
@@ -191,15 +188,15 @@ def render_icon(category, action_id, default):
 
 class AddForm(base.AddForm):
     """Portlet add form.
-    This is registered in configure.zcml. The form_fields variable tells
-    zope.formlib which fields to display. The create() method actually
+    This is registered in configure.zcml. The schema attribute tells
+    plone.autoform which fields to display. The create() method actually
     constructs the assignment that is being added.
     """
-    form_fields = form.Fields(IActionsPortlet)
+    schema = IActionsPortlet
     label = _(u'heading_add_actions_portlet',
               default=u'Add actions portlet')
-    description= _(u'help_add_actions_portlet',
-                   default=u'An action portlet displays actions from a category')
+    description = _(u'help_add_actions_portlet',
+                    default=u'An action portlet displays actions from a category')
 
     def create(self, data):
         return Assignment(**data)
@@ -208,7 +205,7 @@ def create(self, data):
 class EditForm(base.EditForm):
     """Portlet edit form.
 
-    This is registered with configure.zcml. The form_fields variable tells
-    zope.formlib which fields to display.
+    This is registered with configure.zcml. The schema attribute tells
+    plone.autoform which fields to display.
     """
-    form_fields = form.Fields(IActionsPortlet)
+    schema = IActionsPortlet
diff --git a/plone/app/portlets/portlets/base.py b/plone/app/portlets/portlets/base.py
index 94a7a68..84bb600 100644
--- a/plone/app/portlets/portlets/base.py
+++ b/plone/app/portlets/portlets/base.py
@@ -1,22 +1,11 @@
-#import sys
-
 from Acquisition import Explicit
 from OFS.SimpleItem import SimpleItem
-#from ZODB.POSException import ConflictError
-
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from zope.container.contained import Contained
-from zope.interface import implements
-#from zope.interface import Interface
-#from zope.component import adapts
-#from zope.publisher.interfaces.browser import IBrowserView
-
 from plone.app.portlets.interfaces import IDeferredPortletRenderer
 from plone.portlets.interfaces import IPortletAssignment
-#from plone.portlets.interfaces import IPortletDataProvider
-#from plone.portlets.interfaces import IPortletManager
 from plone.portlets.interfaces import IPortletRenderer
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope.container.contained import Contained
+from zope.interface import implements
 
 # Convenience imports
 from plone.app.portlets.browser.formhelper import AddForm
diff --git a/plone/app/portlets/portlets/classic.py b/plone/app/portlets/portlets/classic.py
index c978edf..0d01cca 100644
--- a/plone/app/portlets/portlets/classic.py
+++ b/plone/app/portlets/portlets/classic.py
@@ -1,29 +1,26 @@
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.portlets import base
 from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 from zope import schema
-from zope.formlib import form
 from zope.interface import implements
 
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.portlets import base
-
 
 class IClassicPortlet(IPortletDataProvider):
     """A portlet which can render a classic Plone portlet macro
     """
 
     template = schema.ASCIILine(
-            title=_(u'Template'),
-            description=_(u'The template containing the portlet.'),
-            required=True)
+        title=_(u'Template'),
+        description=_(u'The template containing the portlet.'),
+        required=True)
 
     macro = schema.ASCIILine(
-            title=_(u'Macro'),
-            description=_(u"The macro containing the portlet. "
-                           "Leave blank if there is no macro."),
-            default='portlet',
-            required=False)
+        title=_(u'Macro'),
+        description=_(u"The macro containing the portlet. "
+                      u"Leave blank if there is no macro."),
+        default='portlet',
+        required=False)
 
 
 class Assignment(base.Assignment):
@@ -58,9 +55,10 @@ def path_expression(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(IClassicPortlet)
+    schema = IClassicPortlet
     label = _(u"Add Classic Portlet")
-    description = _(u"A classic portlet allows you to use legacy portlet templates.")
+    description = _(u"A classic portlet allows you to use legacy portlet "
+                    u"templates.")
 
     def create(self, data):
         return Assignment(template=data.get('template', ''),
@@ -68,6 +66,7 @@ def create(self, data):
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(IClassicPortlet)
+    schema = IClassicPortlet
     label = _(u"Edit Classic Portlet")
-    description = _(u"A classic portlet allows you to use legacy portlet templates.")
+    description = _(u"A classic portlet allows you to use legacy portlet "
+                    u"templates.")
diff --git a/plone/app/portlets/portlets/language.py b/plone/app/portlets/portlets/language.py
index b93ffd7..b4b6872 100644
--- a/plone/app/portlets/portlets/language.py
+++ b/plone/app/portlets/portlets/language.py
@@ -1,12 +1,10 @@
-from plone.portlets.interfaces import IPortletDataProvider
 from plone.app.i18n.locales.browser.selector import LanguageSelector
-from zope.component import getMultiAdapter
-from zope.interface import implements
-
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
 from plone.app.portlets import PloneMessageFactory as _
 from plone.app.portlets.portlets import base
+from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope.component import getMultiAdapter
+from zope.interface import implements
 
 
 class ILanguagePortlet(IPortletDataProvider):
@@ -24,18 +22,19 @@ class Renderer(base.Renderer):
 
     def __init__(self, context, request, view, manager, data):
         base.Renderer.__init__(self, context, request, view, manager, data)
-        self.selector=LanguageSelector(context, request, None, None)
+        self.selector = LanguageSelector(context, request, None, None)
         self.selector.update()
-        self.languages=self.selector.languages()
+        self.languages = self.selector.languages()
 
         def key(info):
             return info.get("native", info["name"])
         self.languages.sort(key=key)
-        portal_state = getMultiAdapter((context, request), name='plone_portal_state')
+        portal_state = getMultiAdapter(
+            (context, request), name='plone_portal_state')
         self.navigation_root_url = portal_state.navigation_root_url()
 
     def show(self):
-        return self.selector.available() and len(self.languages)>1
+        return self.selector.available() and len(self.languages) > 1
 
     @property
     def available(self):
diff --git a/plone/app/portlets/portlets/login.py b/plone/app/portlets/portlets/login.py
index e195d8f..4858ad0 100644
--- a/plone/app/portlets/portlets/login.py
+++ b/plone/app/portlets/portlets/login.py
@@ -1,14 +1,12 @@
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.portlets import base
 from plone.memoize.instance import memoize
 from plone.portlets.interfaces import IPortletDataProvider
+from Products.CMFCore.utils import getToolByName
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 from zope.component import getMultiAdapter
 from zope.interface import implements
 
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-from Products.CMFCore.utils import getToolByName
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.portlets import base
-
 
 class ILoginPortlet(IPortletDataProvider):
     """A portlet which can render a login form.
@@ -28,8 +26,10 @@ def __init__(self, context, request, view, manager, data):
 
         self.membership = getToolByName(self.context, 'portal_membership')
 
-        self.context_state = getMultiAdapter((context, request), name='plone_context_state')
-        self.portal_state = getMultiAdapter((context, request), name='plone_portal_state')
+        self.context_state = getMultiAdapter(
+            (context, request), name='plone_context_state')
+        self.portal_state = getMultiAdapter(
+            (context, request), name='plone_portal_state')
         self.pas_info = getMultiAdapter((context, request), name='pas_info')
 
     def show(self):
@@ -80,10 +80,12 @@ def can_register(self):
         if getToolByName(self.context, 'portal_registration', None) is None \
            or not self.join_action():
             return False
-        return self.membership.checkPermission('Add portal member', self.context)
+        return self.membership.checkPermission(
+            'Add portal member', self.context)
 
     def can_request_password(self):
-        return self.membership.checkPermission('Mail forgotten password', self.context)
+        return self.membership.checkPermission(
+            'Mail forgotten password', self.context)
 
     @memoize
     def auth(self, _marker=None):
diff --git a/plone/app/portlets/portlets/navigation.py b/plone/app/portlets/portlets/navigation.py
index bc87d6b..0c7972c 100644
--- a/plone/app/portlets/portlets/navigation.py
+++ b/plone/app/portlets/portlets/navigation.py
@@ -1,31 +1,30 @@
-from plone.i18n.normalizer.interfaces import IIDNormalizer
-from plone.memoize.instance import memoize
-from plone.portlets.interfaces import IPortletDataProvider
-from plone.app.form.widgets.uberselectionwidget import UberSelectionWidget
+from Acquisition import aq_inner, aq_base, aq_parent
+from ComputedAttribute import ComputedAttribute
 from plone.app.layout.navigation.defaultpage import isDefaultPage
-from plone.app.layout.navigation.interfaces import INavtreeStrategy
-from plone.app.layout.navigation.interfaces import INavigationRoot
 from plone.app.layout.navigation.interfaces import INavigationQueryBuilder
+from plone.app.layout.navigation.interfaces import INavigationRoot
+from plone.app.layout.navigation.interfaces import INavtreeStrategy
 from plone.app.layout.navigation.navtree import buildFolderTree
 from plone.app.layout.navigation.root import getNavigationRoot
-from plone.app.vocabularies.catalog import SearchableTextSourceBinder
-from zope.component import adapts, getMultiAdapter, queryUtility
-from zExceptions import NotFound
-from zope.formlib import form
-from zope.interface import implements, Interface
-from zope import schema
-
-from Acquisition import aq_inner, aq_base, aq_parent
-from Products.CMFCore.utils import getToolByName
+from plone.app.layout.navigation.root import getNavigationRootObject
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.portlets import base
+from plone.app.uuid.utils import uuidToObject
+from plone.app.vocabularies.catalog import CatalogSource
+from plone.i18n.normalizer.interfaces import IIDNormalizer
+from plone.memoize.instance import memoize
+from plone.portlets.interfaces import IPortletDataProvider
 from Products.CMFCore.interfaces import ISiteRoot
+from Products.CMFCore.utils import getToolByName
 from Products.CMFDynamicViewFTI.interface import IBrowserDefault
 from Products.CMFPlone import utils
 from Products.CMFPlone.browser.navtree import SitemapNavtreeStrategy
 from Products.CMFPlone.interfaces import INonStructuralFolder
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.portlets import base
+from zExceptions import NotFound
+from zope import schema
+from zope.component import adapts, getMultiAdapter, queryUtility
+from zope.interface import implements, Interface
 
 
 class INavigationPortlet(IPortletDataProvider):
@@ -39,15 +38,15 @@ class INavigationPortlet(IPortletDataProvider):
             default=u"",
             required=False)
 
-    root = schema.Choice(
+    root_uid = schema.Choice(
             title=_(u"label_navigation_root_path", default=u"Root node"),
             description=_(u'help_navigation_root',
                           default=u"You may search for and choose a folder "
                                     "to act as the root of the navigation tree. "
                                     "Leave blank to use the Plone site root."),
             required=False,
-            source=SearchableTextSourceBinder({'is_folderish': True},
-                                              default_query='path:'))
+            source=CatalogSource(is_folderish=True),
+            )
 
     includeTop = schema.Bool(
             title=_(u"label_include_top_node", default=u"Include top node"),
@@ -99,14 +98,15 @@ class Assignment(base.Assignment):
 
     name = ""
     root = None
+    root_uid = None
     currentFolderOnly = False
     includeTop = False
     topLevel = 1
     bottomLevel = 0
 
-    def __init__(self, name="", root=None, currentFolderOnly=False, includeTop=False, topLevel=1, bottomLevel=0):
+    def __init__(self, name="", root_uid=None, currentFolderOnly=False, includeTop=False, topLevel=1, bottomLevel=0):
         self.name = name
-        self.root = root
+        self.root_uid = root_uid
         self.currentFolderOnly = currentFolderOnly
         self.includeTop = includeTop
         self.topLevel = topLevel
@@ -121,6 +121,22 @@ def title(self):
             return self.name
         return _(u'Navigation')
 
+    def _root(self):
+        # This is only called if the instance doesn't have a root_uid
+        # attribute, which is probably because it has an old 'root'
+        # attribute that needs to be converted.
+        root = self.root
+        if not root:
+            return None
+        portal = getToolByName(self, 'portal_url').getPortalObject()
+        navroot = getNavigationRootObject(self, portal)
+        try:
+            root = navroot.unrestrictedTraverse(root.lstrip('/'))
+        except (AttributeError, KeyError, TypeError, NotFound):
+            return
+        return root.UID()
+    root_uid = ComputedAttribute(_root, 1)
+
 
 class Renderer(base.Renderer):
 
@@ -138,7 +154,6 @@ def hasName(self):
 
     @property
     def available(self):
-
         rootpath = self.getNavRootPath()
         if rootpath is None:
             return False
@@ -167,7 +182,7 @@ def heading_link_target(self):
         displaying /sitemap links for anything besides nav root.
         """
 
-        if not self.data.root:
+        if not self.data.root_uid:
             # No particular root item assigned -> should get link to the
             # navigation root sitemap of the current context acquisition chain
             portal_state = getMultiAdapter((self.context, self.request), name="plone_portal_state")
@@ -228,11 +243,7 @@ def getNavRootPath(self):
         currentFolderOnly = self.data.currentFolderOnly or \
                             self.properties.getProperty('currentFolderOnlyInNavtree', False)
         topLevel = self.data.topLevel or self.properties.getProperty('topLevel', 0)
-        root = self.data.root
-        if isinstance(root, unicode):
-            root = str(root)
-
-        return getRootPath(self.context, currentFolderOnly, topLevel, root)
+        return getRootPath(self.context, currentFolderOnly, topLevel, self.data.root_uid)
 
     @memoize
     def getNavRoot(self, _marker=None):
@@ -274,14 +285,13 @@ def render(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(INavigationPortlet)
-    form_fields['root'].custom_widget = UberSelectionWidget
+    schema = INavigationPortlet
     label = _(u"Add Navigation Portlet")
     description = _(u"This portlet displays a navigation tree.")
 
     def create(self, data):
         return Assignment(name=data.get('name', ""),
-                          root=data.get('root', ""),
+                          root_uid=data.get('root_uid', ""),
                           currentFolderOnly=data.get('currentFolderOnly', False),
                           includeTop=data.get('includeTop', False),
                           topLevel=data.get('topLevel', 0),
@@ -289,8 +299,7 @@ def create(self, data):
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(INavigationPortlet)
-    form_fields['root'].custom_widget = UberSelectionWidget
+    schema = INavigationPortlet
     label = _(u"Edit Navigation Portlet")
     description = _(u"This portlet displays a navigation tree.")
 
@@ -317,8 +326,11 @@ def __init__(self, context, portlet):
             query = {}
 
         # Construct the path query
-
-        rootPath = getNavigationRoot(context, relativeRoot=portlet.root)
+        root = uuidToObject(portlet.root_uid)
+        if root is not None:
+            rootPath = '/'.join(root.getPhysicalPath())
+        else:
+            rootPath = getNavigationRoot(context)
         currentPath = '/'.join(context.getPhysicalPath())
 
         # If we are above the navigation root, a navtree query would return
@@ -377,7 +389,7 @@ def __init__(self, context, portlet):
             navtree_properties.getProperty('currentFolderOnlyInNavtree', False)
 
         topLevel = portlet.topLevel or navtree_properties.getProperty('topLevel', 0)
-        self.rootPath = getRootPath(context, currentFolderOnly, topLevel, portlet.root)
+        self.rootPath = getRootPath(context, currentFolderOnly, topLevel, portlet.root_uid)
 
     def subtreeFilter(self, node):
         sitemapDecision = SitemapNavtreeStrategy.subtreeFilter(self, node)
@@ -409,7 +421,11 @@ def getRootPath(context, currentFolderOnly, topLevel, root):
         else:
             return '/'.join(context.getPhysicalPath())
 
-    rootPath = getNavigationRoot(context, relativeRoot=root)
+    root = uuidToObject(root)
+    if root is not None:
+        rootPath = '/'.join(root.getPhysicalPath())
+    else:
+        rootPath = getNavigationRoot(context)
 
     # Adjust for topLevel
     if topLevel > 0:
diff --git a/plone/app/portlets/portlets/news.py b/plone/app/portlets/portlets/news.py
index 8b2e3f0..b696b9d 100644
--- a/plone/app/portlets/portlets/news.py
+++ b/plone/app/portlets/portlets/news.py
@@ -1,20 +1,17 @@
+from Acquisition import aq_inner
+from plone.app.layout.navigation.root import getNavigationRootObject
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.cache import render_cachekey
+from plone.app.portlets.portlets import base
 from plone.memoize import ram
 from plone.memoize.compress import xhtml_compress
 from plone.memoize.instance import memoize
 from plone.portlets.interfaces import IPortletDataProvider
-from plone.app.layout.navigation.root import getNavigationRootObject
-from zope.component import getMultiAdapter
-from zope.formlib import form
-from zope.interface import implements
-from zope import schema
-
-from Acquisition import aq_inner
 from Products.CMFCore.utils import getToolByName
 from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.cache import render_cachekey
-from plone.app.portlets.portlets import base
+from zope import schema
+from zope.component import getMultiAdapter
+from zope.interface import implements
 
 
 class INewsPortlet(IPortletDataProvider):
@@ -24,13 +21,14 @@ class INewsPortlet(IPortletDataProvider):
                        required=True,
                        default=5)
 
-    state = schema.Tuple(title=_(u"Workflow state"),
-                         description=_(u"Items in which workflow state to show."),
-                         default=('published', ),
-                         required=True,
-                         value_type=schema.Choice(
-                             vocabulary="plone.app.vocabularies.WorkflowStates")
-                         )
+    state = schema.Tuple(
+        title=_(u"Workflow state"),
+        description=_(u"Items in which workflow state to show."),
+        default=('published', ),
+        required=True,
+        value_type=schema.Choice(
+            vocabulary="plone.app.vocabularies.WorkflowStates")
+        )
 
 
 class Assignment(base.Assignment):
@@ -65,8 +63,8 @@ def published_news_items(self):
 
     def all_news_link(self):
         context = aq_inner(self.context)
-        portal_state = getMultiAdapter((context, self.request),
-            name='plone_portal_state')
+        portal_state = getMultiAdapter(
+            (context, self.request), name='plone_portal_state')
         portal = portal_state.portal()
         if 'news' in getNavigationRootObject(context, portal).objectIds():
             return '%s/news' % portal_state.navigation_root_url()
@@ -76,8 +74,8 @@ def all_news_link(self):
     def _data(self):
         context = aq_inner(self.context)
         catalog = getToolByName(context, 'portal_catalog')
-        portal_state = getMultiAdapter((context, self.request),
-            name='plone_portal_state')
+        portal_state = getMultiAdapter(
+            (context, self.request), name='plone_portal_state')
         path = portal_state.navigation_root_path()
         limit = self.data.count
         state = self.data.state
@@ -90,15 +88,18 @@ def _data(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(INewsPortlet)
+    schema = INewsPortlet
     label = _(u"Add News Portlet")
     description = _(u"This portlet displays recent News Items.")
 
     def create(self, data):
-        return Assignment(count=data.get('count', 5), state=data.get('state', ('published', )))
+        return Assignment(
+            count=data.get('count', 5),
+            state=data.get('state', ('published', )),
+            )
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(INewsPortlet)
+    schema = INewsPortlet
     label = _(u"Edit News Portlet")
     description = _(u"This portlet displays recent News Items.")
diff --git a/plone/app/portlets/portlets/recent.py b/plone/app/portlets/portlets/recent.py
index bdb5362..1615f27 100644
--- a/plone/app/portlets/portlets/recent.py
+++ b/plone/app/portlets/portlets/recent.py
@@ -1,18 +1,15 @@
+from Acquisition import aq_inner
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.cache import render_cachekey
+from plone.app.portlets.portlets import base
 from plone.memoize import ram
 from plone.memoize.compress import xhtml_compress
 from plone.memoize.instance import memoize
 from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope import schema
 from zope.component import getMultiAdapter
-from zope.formlib import form
 from zope.interface import implements
-from zope import schema
-
-from Acquisition import aq_inner
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.cache import render_cachekey
-from plone.app.portlets.portlets import base
 
 
 class IRecentPortlet(IPortletDataProvider):
@@ -49,13 +46,15 @@ def __init__(self, *args):
         base.Renderer.__init__(self, *args)
 
         context = aq_inner(self.context)
-        portal_state = getMultiAdapter((context, self.request), name='plone_portal_state')
+        portal_state = getMultiAdapter(
+            (context, self.request), name='plone_portal_state')
         self.anonymous = portal_state.anonymous()
         self.navigation_root_url = portal_state.navigation_root_url()
         self.typesToShow = portal_state.friendly_types()
         self.navigation_root_path = portal_state.navigation_root_path()
 
-        plone_tools = getMultiAdapter((context, self.request), name='plone_tools')
+        plone_tools = getMultiAdapter(
+            (context, self.request), name='plone_tools')
         self.catalog = plone_tools.catalog()
 
     @ram.cache(_render_cachekey)
@@ -64,9 +63,7 @@ def render(self):
 
     @property
     def available(self):
-        return not self.anonymous and \
-               self.data.count > 0 and \
-               len(self._data())
+        return not self.anonymous and self.data.count > 0 and len(self._data())
 
     def recent_items(self):
         return self._data()
@@ -76,7 +73,6 @@ def recently_modified_link(self):
 
     @memoize
     def _data(self):
-        context = aq_inner(self.context)
         limit = self.data.count
         path = self.navigation_root_path
         return self.catalog(portal_type=self.typesToShow,
@@ -87,7 +83,7 @@ def _data(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(IRecentPortlet)
+    schema = IRecentPortlet
     label = _(u"Add Recent Portlet")
     description = _(u"This portlet displays recently modified content.")
 
@@ -96,6 +92,6 @@ def create(self, data):
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(IRecentPortlet)
+    schema = IRecentPortlet
     label = _(u"Edit Recent Portlet")
     description = _(u"This portlet displays recently modified content.")
diff --git a/plone/app/portlets/portlets/review.py b/plone/app/portlets/portlets/review.py
index 7ff4e2b..c56cec7 100644
--- a/plone/app/portlets/portlets/review.py
+++ b/plone/app/portlets/portlets/review.py
@@ -1,21 +1,17 @@
+from Acquisition import aq_inner
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.portlets import base
 from plone.i18n.normalizer.interfaces import IIDNormalizer
 from plone.memoize.instance import memoize
 from plone.portlets.interfaces import IPortletDataProvider
+from Products.CMFCore.utils import getToolByName
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 from zope.component import getMultiAdapter
 from zope.component import queryUtility
-from zope.formlib import form
 from zope.interface import implements
 
-from Acquisition import aq_inner
-from Products.CMFCore.utils import getToolByName
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.portlets import base
-
 
 class IReviewPortlet(IPortletDataProvider):
-
     pass
 
 
@@ -82,22 +78,23 @@ def _data(self):
                 creator_name = creator_id
 
             items.append(dict(
-                path = obj.absolute_url(),
-                title = obj.pretty_title_or_id(),
-                description = obj.Description(),
-                icon = getIcon(obj).html_tag(),
-                creator = creator_name,
-                review_state = review_state,
-                review_state_class = 'state-%s ' % norm(review_state),
-                mod_date = toLocalizedTime(obj.ModificationDate()),
+                path=obj.absolute_url(),
+                title=obj.pretty_title_or_id(),
+                description=obj.Description(),
+                icon=getIcon(obj).html_tag(),
+                creator=creator_name,
+                review_state=review_state,
+                review_state_class='state-%s ' % norm(review_state),
+                mod_date=toLocalizedTime(obj.ModificationDate()),
             ))
         return items
 
 
 class AddForm(base.NullAddForm):
-    form_fields = form.Fields(IReviewPortlet)
+    schema = IReviewPortlet
     label = _(u"Add Review Portlet")
-    description = _(u"This portlet displays a queue of documents awaiting review.")
+    description = _(u"This portlet displays a queue of documents awaiting "
+                    u"review.")
 
     def create(self):
         return Assignment()
diff --git a/plone/app/portlets/portlets/rss.py b/plone/app/portlets/portlets/rss.py
index 39a73d8..485cbb6 100644
--- a/plone/app/portlets/portlets/rss.py
+++ b/plone/app/portlets/portlets/rss.py
@@ -1,18 +1,14 @@
-from logging import getLogger
-import time
-
-import feedparser
-from plone.portlets.interfaces import IPortletDataProvider
-from zope.formlib import form
-from zope.interface import implements, Interface
-from zope import schema
-
 from DateTime import DateTime
 from DateTime.interfaces import DateTimeError
-from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
-
+from logging import getLogger
 from plone.app.portlets import PloneMessageFactory as _
 from plone.app.portlets.portlets import base
+from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ZopeTwoPageTemplateFile
+from zope import schema
+from zope.interface import implements, Interface
+import feedparser
+import time
 
 
 # Accept these bozo_exceptions encountered by feedparser when parsing
@@ -24,6 +20,7 @@
 
 logger = getLogger(__name__)
 
+
 class IFeed(Interface):
 
     def __init__(url, timeout):
@@ -83,8 +80,8 @@ def __init__(self, url, timeout):
         self._siteurl = ""
         self._loaded = False    # is the feed loaded
         self._failed = False    # does it fail at the last update?
-        self._last_update_time_in_minutes = 0 # when was the feed last updated?
-        self._last_update_time = None            # time as DateTime or Nonw
+        self._last_update_time_in_minutes = 0  # when was the feed last updated?
+        self._last_update_time = None  # time as DateTime or Nonw
 
     @property
     def last_update_time_in_minutes(self):
@@ -112,8 +109,8 @@ def loaded(self):
     @property
     def needs_update(self):
         """check if this feed needs updating"""
-        now = time.time()/60
-        return (self.last_update_time_in_minutes+self.timeout) < now
+        now = time.time() / 60
+        return (self.last_update_time_in_minutes + self.timeout) < now
 
     def update(self):
         """update this feed"""
@@ -156,13 +153,14 @@ def _buildItemDict(self, item):
     def _retrieveFeed(self):
         """do the actual work and try to retrieve the feed"""
         url = self.url
-        if url!='':
-            self._last_update_time_in_minutes = time.time()/60
+        if url != '':
+            self._last_update_time_in_minutes = time.time() / 60
             self._last_update_time = DateTime()
             d = feedparser.parse(url)
-            if getattr(d, 'bozo', 0) == 1 and not isinstance(d.get('bozo_exception'),
-                                              ACCEPTED_FEEDPARSER_EXCEPTIONS):
-                self._loaded = True # we tried at least but have a failed load
+            if (getattr(d, 'bozo', 0) == 1
+                    and not isinstance(d.get('bozo_exception'),
+                                       ACCEPTED_FEEDPARSER_EXCEPTIONS)):
+                self._loaded = True  # we tried at least but have a failed load
                 self._failed = True
                 return False
             try:
@@ -185,8 +183,8 @@ def _retrieveFeed(self):
             self._failed = False
             return True
         self._loaded = True
-        self._failed = True # no url set means failed
-        return False # no url set, although that actually should not really happen
+        self._failed = True  # no url set means failed
+        return False  # no url set, although that should not really happen
 
     @property
     def items(self):
@@ -215,23 +213,29 @@ class IRSSPortlet(IPortletDataProvider):
 
     portlet_title = schema.TextLine(
         title=_(u'Title'),
-        description=_(u'Title of the portlet.  If omitted, the title of the feed will be used.'),
+        description=_(u'Title of the portlet.  If omitted, the title of the '
+                      u'feed will be used.'),
         required=False,
         default=u'')
 
-    count = schema.Int(title=_(u'Number of items to display'),
-                       description=_(u'How many items to list.'),
-                       required=True,
-                       default=5)
-    url = schema.TextLine(title=_(u'URL of RSS feed'),
-                        description=_(u'Link of the RSS feed to display.'),
-                        required=True,
-                        default=u'')
+    count = schema.Int(
+        title=_(u'Number of items to display'),
+        description=_(u'How many items to list.'),
+        required=True,
+        default=5)
 
-    timeout = schema.Int(title=_(u'Feed reload timeout'),
-                        description=_(u'Time in minutes after which the feed should be reloaded.'),
-                        required=True,
-                        default=100)
+    url = schema.TextLine(
+        title=_(u'URL of RSS feed'),
+        description=_(u'Link of the RSS feed to display.'),
+        required=True,
+        default=u'')
+
+    timeout = schema.Int(
+        title=_(u'Feed reload timeout'),
+        description=_(u'Time in minutes after which the feed should be '
+                      u'reloaded.'),
+        required=True,
+        default=100)
 
 
 class Assignment(base.Assignment):
@@ -244,9 +248,9 @@ def title(self):
         """return the title with RSS feed title or from URL"""
         feed = FEED_DATA.get(self.data.url, None)
         if feed is None:
-            return u'RSS: '+self.url[:20]
+            return u'RSS: ' + self.url[:20]
         else:
-            return u'RSS: '+feed.title[:20]
+            return u'RSS: ' + feed.title[:20]
 
     def __init__(self, portlet_title=u'', count=5, url=u"", timeout=100):
         self.portlet_title = portlet_title
@@ -262,7 +266,7 @@ class Renderer(base.DeferredRenderer):
     @property
     def initializing(self):
         """should return True if deferred template should be displayed"""
-        feed=self._getFeed()
+        feed = self._getFeed()
         if not feed.loaded:
             return True
         if feed.needs_update:
@@ -322,18 +326,19 @@ def enabled(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(IRSSPortlet)
+    schema = IRSSPortlet
     label = _(u"Add RSS Portlet")
     description = _(u"This portlet displays an RSS feed.")
 
     def create(self, data):
-        return Assignment(portlet_title=data.get('portlet_title', u''),
-                          count=data.get('count', 5),
-                          url = data.get('url', ''),
-                          timeout = data.get('timeout', 100))
+        return Assignment(
+            portlet_title=data.get('portlet_title', u''),
+            count=data.get('count', 5),
+            url=data.get('url', ''),
+            timeout=data.get('timeout', 100))
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(IRSSPortlet)
+    schema = IRSSPortlet
     label = _(u"Edit RSS Portlet")
     description = _(u"This portlet displays an RSS feed.")
diff --git a/plone/app/portlets/portlets/search.py b/plone/app/portlets/portlets/search.py
index c47214b..8569dcf 100644
--- a/plone/app/portlets/portlets/search.py
+++ b/plone/app/portlets/portlets/search.py
@@ -1,13 +1,10 @@
+from plone.app.portlets import PloneMessageFactory as _
+from plone.app.portlets.portlets import base
 from plone.portlets.interfaces import IPortletDataProvider
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope import schema
 from zope.component import getMultiAdapter
-from zope.formlib import form
 from zope.interface import implements
-from zope import schema
-
-from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
-
-from plone.app.portlets import PloneMessageFactory as _
-from plone.app.portlets.portlets import base
 
 
 class ISearchPortlet(IPortletDataProvider):
@@ -15,19 +12,19 @@ class ISearchPortlet(IPortletDataProvider):
     """
 
     enableLivesearch = schema.Bool(
-            title = _(u"Enable LiveSearch"),
-            description = _(u"Enables the LiveSearch feature, which shows "
-                             "live results if the browser supports "
-                             "JavaScript."),
-            default = True,
-            required = False)
+        title=_(u"Enable LiveSearch"),
+        description=_(u"Enables the LiveSearch feature, which shows "
+                      u"live results if the browser supports "
+                      u"JavaScript."),
+        default=True,
+        required=False)
 
 
 class Assignment(base.Assignment):
     implements(ISearchPortlet)
 
     def __init__(self, enableLivesearch=True):
-        self.enableLivesearch=enableLivesearch
+        self.enableLivesearch = enableLivesearch
 
     @property
     def title(self):
@@ -41,7 +38,8 @@ class Renderer(base.Renderer):
     def __init__(self, context, request, view, manager, data):
         base.Renderer.__init__(self, context, request, view, manager, data)
 
-        portal_state = getMultiAdapter((context, request), name='plone_portal_state')
+        portal_state = getMultiAdapter(
+            (context, request), name='plone_portal_state')
         self.navigation_root_url = portal_state.navigation_root_url()
 
     def enable_livesearch(self):
@@ -52,7 +50,7 @@ def search_action(self):
 
 
 class AddForm(base.AddForm):
-    form_fields = form.Fields(ISearchPortlet)
+    schema = ISearchPortlet
     label = _(u"Add Search Portlet")
     description = _(u"This portlet shows a search box.")
 
@@ -61,6 +59,6 @@ def create(self, data):
 
 
 class EditForm(base.EditForm):
-    form_fields = form.Fields(ISearchPortlet)
+    schema = ISearchPortlet
     label = _(u"Edit Search Portlet")
     description = _(u"This portlet shows a search box.")
diff --git a/plone/app/portlets/tests/profiles/z3ctesting/portlets.xml b/plone/app/portlets/tests/profiles/z3ctesting/portlets.xml
deleted file mode 100644
index c65fa97..0000000
--- a/plone/app/portlets/tests/profiles/z3ctesting/portlets.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0"?>
-<portlets
-    xmlns:i18n="http://xml.zope.org/namespaces/i18n"
-    i18n:domain="plone">
-
-
-    <portlet
-        addview="portlet.z3cTest"
-        title="Test portlet"
-        description="A test portlet"
-        i18n:attributes="title title_test_portlet;
-                         description description_test_portlet"
-        />
-
-</portlets>
diff --git a/plone/app/portlets/tests/test_configuration.py b/plone/app/portlets/tests/test_configuration.py
index a6bbb01..0f11c58 100644
--- a/plone/app/portlets/tests/test_configuration.py
+++ b/plone/app/portlets/tests/test_configuration.py
@@ -56,7 +56,6 @@ class DummyView(BrowserView):
 
 from zope.interface import implements
 from zope import schema
-from zope.formlib import form
 
 from plone.portlets.interfaces import IPortletDataProvider
 from plone.app.portlets.portlets import base
@@ -86,7 +85,7 @@ def render(self):
 
 
 class TestAddForm(base.AddForm):
-    form_fields = form.Fields(ITestPortlet)
+    schema = ITestPortlet
     label = u"Test portlet"
 
     def create(self, data):
@@ -96,7 +95,7 @@ def create(self, data):
 
 
 class TestEditForm(base.EditForm):
-    form_fields = form.Fields(ITestPortlet)
+    schema = ITestPortlet
     label = u"Test portlet"
 
 
@@ -535,9 +534,9 @@ def testExport(self):
   <property name="topLevel">1</property>
   <property name="currentFolderOnly">False</property>
   <property name="name"></property>
-  <property name="includeTop">False</property>
+  <property name="root_uid"/>
   <property name="bottomLevel">0</property>
-  <property name="root"></property>
+  <property name="includeTop">False</property>
  </assignment>
  <blacklist category="user" location="/" manager="test.testcolumn"
     status="acquire"/>
diff --git a/plone/app/portlets/tests/test_navigation_portlet.py b/plone/app/portlets/tests/test_navigation_portlet.py
index e4678ba..92265f6 100644
--- a/plone/app/portlets/tests/test_navigation_portlet.py
+++ b/plone/app/portlets/tests/test_navigation_portlet.py
@@ -1,6 +1,11 @@
 from zope.component import getUtility, getMultiAdapter
 from zope.interface import directlyProvides
 
+from five.intid.intid import IntIds
+from five.intid.site import addUtility
+from zope.component import getSiteManager
+from zope.intid.interfaces import IIntIds
+
 from Products.GenericSetup.utils import _getDottedName
 
 from plone.portlets.interfaces import IPortletType
@@ -22,6 +27,9 @@
 class TestPortlet(PortletsTestCase):
 
     def afterSetUp(self):
+        sm = getSiteManager(self.portal)
+        addUtility(sm, IIntIds, IntIds, ofs_name='intids', findroot=False)
+
         self.setRoles(('Manager', ))
 
     def testPortletTypeRegistered(self):
@@ -74,6 +82,9 @@ def testRenderer(self):
 class TestRenderer(PortletsTestCase):
 
     def afterSetUp(self):
+        sm = getSiteManager(self.portal)
+        addUtility(sm, IIntIds, IntIds, ofs_name='intids', findroot=False)
+
         self.populateSite()
 
     def renderer(self, context=None, request=None, view=None, manager=None, assignment=None):
@@ -265,7 +276,7 @@ def testIncludeTopWithoutNavigationRoot(self):
         self.portal.folder2.invokeFactory('Folder', 'folder21')
         self.portal.folder2.folder21.invokeFactory('Document', 'doc211')
         view = self.renderer(self.portal.folder2.folder21,
-            assignment=navigation.Assignment(topLevel=0, root=None, includeTop=True))
+            assignment=navigation.Assignment(topLevel=0, root_uid=None, includeTop=True))
         tree = view.getNavTree()
         self.failUnless(tree)
         self.failUnless(view.root_is_portal())
@@ -276,7 +287,7 @@ def testTopLevelWithNavigationRoot(self):
         self.portal.folder2.invokeFactory('Folder', 'folder21')
         self.portal.folder2.folder21.invokeFactory('Document', 'doc211')
         view = self.renderer(self.portal.folder2.folder21,
-            assignment=navigation.Assignment(topLevel=1, root='/folder2'))
+            assignment=navigation.Assignment(topLevel=1, root_uid=self.portal.folder2.UID()))
         tree = view.getNavTree()
         self.assertTrue(tree)
         self.assertEqual(len(tree['children']), 1)
@@ -290,14 +301,14 @@ def testMultipleTopLevelWithNavigationRoot(self):
         self.portal.invokeFactory('Folder', 'abcde')
         self.portal.abc.invokeFactory('Folder', 'down_abc')
         self.portal.abcde.invokeFactory('Folder', 'down_abcde')
-        view1 = self.renderer(self.portal.abc, assignment=navigation.Assignment(topLevel=0, root='/abc'))
-        view2 = self.renderer(self.portal.abc, assignment=navigation.Assignment(topLevel=0, root='/abcde'))
+        view1 = self.renderer(self.portal.abc, assignment=navigation.Assignment(topLevel=0, root_uid=self.portal.abc.UID()))
+        view2 = self.renderer(self.portal.abc, assignment=navigation.Assignment(topLevel=0, root_uid=self.portal.abcde.UID()))
         tree1 = view1.getNavTree()
         tree2 = view2.getNavTree()
         self.assertEqual(len(tree1['children']), 1)
         self.assertEqual(len(tree2['children']), 1)
-        view1 = self.renderer(self.portal.abcde, assignment=navigation.Assignment(topLevel=0, root='/abc'))
-        view2 = self.renderer(self.portal.abcde, assignment=navigation.Assignment(topLevel=0, root='/abcde'))
+        view1 = self.renderer(self.portal.abcde, assignment=navigation.Assignment(topLevel=0, root_uid=self.portal.abc.UID()))
+        view2 = self.renderer(self.portal.abcde, assignment=navigation.Assignment(topLevel=0, root_uid=self.portal.abcde.UID()))
         tree1 = view1.getNavTree()
         tree2 = view2.getNavTree()
         self.assertEqual(len(tree2['children']), 1)
@@ -340,35 +351,28 @@ def testNavRootWithUnicodeNavigationRoot(self):
         self.portal.folder2.invokeFactory('Folder', 'folder21')
         self.portal.folder2.folder21.invokeFactory('Document', 'doc211')
         view = self.renderer(self.portal.folder2.folder21,
-            assignment=navigation.Assignment(topLevel=1, root=u'/folder2'))
+            assignment=navigation.Assignment(topLevel=1, root_uid=self.portal.folder2.UID()))
         self.assertEqual(view.getNavRootPath(), '/plone/folder2/folder21')
         self.assertEqual(view.getNavRoot().absolute_url(),
                          self.portal.folder2.folder21.absolute_url())
 
     def testNoRootSet(self):
-        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root='', topLevel=0))
-        tree = view.getNavTree()
-        self.assertTrue(tree)
-        self.assertEqual(tree['children'][-1]['item'].getPath(), '/plone/folder2')
-
-    def testRootIsPortal(self):
-        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root='/', topLevel=0))
+        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root_uid='', topLevel=0))
         tree = view.getNavTree()
         self.assertTrue(tree)
         self.assertEqual(tree['children'][-1]['item'].getPath(), '/plone/folder2')
 
     def testRootIsNotPortal(self):
-        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root='/folder2', topLevel=0))
+        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root_uid=self.portal.folder2.UID(), topLevel=0))
         tree = view.getNavTree()
         self.assertTrue(tree)
         self.assertEqual(tree['children'][0]['item'].getPath(), '/plone/folder2/doc21')
 
     def testRootDoesNotExist(self):
-        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root='/dodo', topLevel=0))
+        view = self.renderer(self.portal.folder2.file21, assignment=navigation.Assignment(root_uid='DOESNT_EXIST', topLevel=0))
         tree = view.getNavTree()
         self.assertTrue(tree)
-        self.assertEqual(tree.get('item', None), None)
-        self.assertEqual(len(tree['children']), 0)
+        self.assertEqual(len(tree['children']), 6)
 
     def testAboveRoot(self):
         ntp=self.portal.portal_properties.navtree_properties
@@ -379,7 +383,7 @@ def testAboveRoot(self):
         self.assertEqual(tree['children'][0]['item'].getPath(), '/plone/folder2/doc21')
 
     def testOutsideRoot(self):
-        view = self.renderer(self.portal.folder1, assignment=navigation.Assignment(root='/folder2'))
+        view = self.renderer(self.portal.folder1, assignment=navigation.Assignment(root_uid=self.portal.folder2.UID()))
         tree = view.getNavTree()
         self.assertTrue(tree)
         self.assertEqual(tree['children'][0]['item'].getPath(), '/plone/folder2/doc21')
@@ -497,7 +501,7 @@ def testPortletNotDisplayedOnINavigationRoot(self):
 
         # make a navigation portlet
         assignment = navigation.Assignment(bottomLevel=0, topLevel=1,
-                root=None)
+                root_uid=None)
         portlet = self.renderer(self.portal.folder1, assignment=assignment)
 
         # check there is no portlet
@@ -519,7 +523,7 @@ def testINavigationRootWithRelativeRootSet(self):
 
         # make a navigation portlet with navigation root set
         assignment = navigation.Assignment(bottomLevel=0, topLevel=0,
-                root='/folder1/folder1_1')
+                root_uid=self.portal.folder1.folder1_1.UID())
         portlet = self.renderer(self.portal.folder1.folder1_1,
                 assignment=assignment)
 
@@ -585,7 +589,7 @@ def testHeadingLinkRooted(self):
         """
         See that heading link points to a content item if root selected, otherwise sitemap.
         """
-        view = self.renderer(self.portal.folder2, assignment=navigation.Assignment(topLevel=0, root="/folder2"))
+        view = self.renderer(self.portal.folder2, assignment=navigation.Assignment(topLevel=0, root_uid=self.portal.folder2.UID()))
         link = view.heading_link_target()
         self.assertEqual(link, 'http://nohost/plone/folder2')
 
@@ -593,7 +597,7 @@ def testHeadingLinkRootedItemGone(self):
         """
         See that heading link points to a content item which do not exist
         """
-        view = self.renderer(self.portal.folder2, assignment=navigation.Assignment(topLevel=0, root="/plone/foobar"))
+        view = self.renderer(self.portal.folder2, assignment=navigation.Assignment(topLevel=0, root_uid="DOESNT_EXIST"))
         link = view.heading_link_target()
         # Points to the site root if the item is gone
         self.assertEqual(link, "http://nohost/plone/sitemap")
diff --git a/plone/app/portlets/tests/test_z3cforms.py b/plone/app/portlets/tests/test_z3cforms.py
deleted file mode 100644
index dda8ef5..0000000
--- a/plone/app/portlets/tests/test_z3cforms.py
+++ /dev/null
@@ -1,158 +0,0 @@
-import time
-from z3c.form import field
-from zope import schema
-from zope.component import getUtility, getMultiAdapter, queryMultiAdapter
-from zope.interface import implements
-from zope.site.hooks import setHooks, setSite
-
-from Products.PloneTestCase.layer import PloneSite
-
-from plone.portlets.interfaces import IPortletType
-from plone.portlets.interfaces import IPortletManager
-from plone.portlets.interfaces import IPortletAssignment
-from plone.portlets.interfaces import IPortletDataProvider
-from plone.portlets.interfaces import IPortletRenderer
-from plone.app.portlets.portlets import base
-from plone.app.portlets.browser import z3cformhelper
-from plone.app.portlets.storage import PortletAssignmentMapping
-from plone.app.portlets.tests.base import PortletsTestCase
-# BBB Zope 2.12
-try:
-    from Zope2.App import zcml
-    from OFS import metaconfigure
-    zcml # pyflakes
-    metaconfigure
-except ImportError:
-    from Products.Five import zcml
-    from Products.Five import fiveconfigure as metaconfigure
-
-
-class Iz3cPortlet(IPortletDataProvider):
-    """A dummy z3c portlet.
-    """
-
-    foo = schema.Text(title=u"Foo")
-
-
-class Assignment(base.Assignment):
-
-    implements(Iz3cPortlet)
-
-    def __init__(self, foo=u''):
-        self.foo = foo
-
-
-class Renderer(base.Renderer):
-
-    def render(self, context, request):
-        return self.data.foo
-
-
-class AddForm(z3cformhelper.AddForm):
-
-    fields = field.Fields(Iz3cPortlet)
-
-    def create(self, data):
-        return Assignment(**data)
-
-
-class EditForm(z3cformhelper.EditForm):
-
-    fields = field.Fields(Iz3cPortlet)
-
-
-zcml_string = """\
-<configure xmlns="http://namespaces.zope.org/zope"
-           xmlns:plone="http://namespaces.plone.org/plone"
-           xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
-           package="plone.app.portlets"
-           i18n_domain="test">
-
-    <plone:portlet
-        name="portlet.z3cTest"
-        interface="plone.app.portlets.tests.test_z3cforms.Iz3cPortlet"
-        assignment="plone.app.portlets.tests.test_z3cforms.Assignment"
-        renderer="plone.app.portlets.tests.test_z3cforms.Renderer"
-        addview="plone.app.portlets.tests.test_z3cforms.AddForm"
-        editview="plone.app.portlets.tests.test_z3cforms.EditForm"
-        />
-
-    <genericsetup:registerProfile
-        name="z3ctesting"
-        title="plone.app.portlets z3c testing"
-        description="Used for testing only"
-        directory="tests/profiles/z3ctesting"
-        for="Products.CMFCore.interfaces.ISiteRoot"
-        provides="Products.GenericSetup.interfaces.EXTENSION"
-        />
-
-</configure>
-"""
-
-
-class z3cPortletZCMLLayer(PloneSite):
-
-    @classmethod
-    def setUp(cls):
-        metaconfigure.debug_mode = True
-        zcml.load_string(zcml_string)
-        metaconfigure.debug_mode = False
-
-    @classmethod
-    def tearDown(cls):
-        pass
-
-
-class TestPortlet(PortletsTestCase):
-
-    layer = z3cPortletZCMLLayer
-
-    def afterSetUp(self):
-        setHooks()
-        setSite(self.portal)
-        self.setRoles(('Manager', ))
-        portal_setup = self.portal.portal_setup
-        # wait a bit or we get duplicate ids on import
-        time.sleep(0.2)
-        portal_setup.runAllImportStepsFromProfile('profile-plone.app.portlets:z3ctesting')
-
-    def testInterfaces(self):
-        portlet = Assignment()
-        self.assertTrue(IPortletAssignment.providedBy(portlet))
-        self.assertTrue(IPortletDataProvider.providedBy(portlet.data))
-
-    def testInvokeAddview(self):
-        portlet = getUtility(IPortletType, name='portlet.z3cTest')
-        mapping = self.portal.restrictedTraverse('++contextportlets++plone.leftcolumn')
-        for m in mapping.keys():
-            del mapping[m]
-
-        addview = mapping.restrictedTraverse('+/' + portlet.addview)
-        addview.createAndAdd(data={'foo': 'bar'})
-
-        self.assertEqual(len(mapping), 1)
-        self.assertTrue(isinstance(mapping.values()[0], Assignment))
-
-    def testInvokeEditView(self):
-        mapping = PortletAssignmentMapping()
-        request = self.folder.REQUEST
-        mapping['foo'] = Assignment(foo='bar')
-        editview = queryMultiAdapter((mapping['foo'], request), name='edit', default=None)
-        self.assertTrue(editview is not None)
-
-    def testRenderer(self):
-        context = self.folder
-        request = self.folder.REQUEST
-        view = self.folder.restrictedTraverse('@@plone')
-        manager = getUtility(IPortletManager, name='plone.leftcolumn', context=self.portal)
-        assignment = Assignment(foo='bar')
-        renderer = getMultiAdapter((context, request, view, manager, assignment), IPortletRenderer)
-        self.assertTrue(isinstance(renderer, Renderer))
-        self.assertEqual(renderer.render(context, request), 'bar')
-
-
-def test_suite():
-    from unittest import TestSuite, makeSuite
-    suite = TestSuite()
-    suite.addTest(makeSuite(TestPortlet))
-    return suite
diff --git a/setup.py b/setup.py
index 27332e6..25f7a9a 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = '2.5.1.dev0'
+version = '3.0.dev0'
 
 setup(name='plone.app.portlets',
       version=version,
@@ -32,15 +32,13 @@
       ),
       install_requires=[
         'setuptools',
-        'five.formlib',
         'five.customerize',
         'plone.i18n',
         'plone.memoize',
         'plone.portlets>=1.1',
-        'plone.app.form',
         'plone.app.i18n',
         'plone.app.layout >= 1.2dev',
-        'plone.app.vocabularies',
+        'plone.app.vocabularies >= 2.1.15.dev0',
         'transaction',
         'zope.annotation',
         'zope.browser',
@@ -49,7 +47,6 @@
         'zope.container',
         'zope.contentprovider',
         'zope.event',
-        'zope.formlib',
         'zope.i18nmessageid',
         'zope.interface',
         'zope.lifecycleevent',




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


More information about the Testbot mailing list