[Checkins] SVN: zope.publisher/trunk/ Make the default skin apply pattern adaptable for other
Roger Ineichen
roger at projekt01.ch
Wed Mar 4 19:47:39 EST 2009
Log message for revision 97505:
Make the default skin apply pattern adaptable for other
requests which are not based on IBrowserRequest.
A skin must provide ISkinType (IBrowserSkinType does that)
and a request must provide ISkinnable for apply a skin.
This is 100% compatible with the previous implementation
since the default adapter is configured in zcml (grok?)
- Fix: ensure that we only apply skin interface in setDefaultSkin which also
provide IBrowserSkinType. This will ensure that we find a skin if the
applySkin method will lookup for a skin based on this type interface.
- Fix: Make it possible to use adapters and not only interfaces as skins from
the adapter registry. Right now the defaultSkin directive registers simple
interfaces as skin adapters which will run into a TypeError if someone tries
to adapter such a skin adapter. Probably we should change the defaultSkin
directive and register real adapters instead of using the interfaces as fake
adapters where we expect adapter factories.
- Feature: allow to use applySkin with different skin types using the optional
argument skinType which is by default set to IBrowserSkinType
- Feature: implemented the default skin pattern within adapters. This allows
us to register default skins for other requests then only IBrowserRequest
using IDefaultSkin adapters.
Note, ISkinnable and ISkinType and the skin implementation should be moved
out of the browser request modules. Packages like z3c.jsonrpc do not depend
on IBrowserRequest but they are skinnable.
- update tests
Changed:
U zope.publisher/trunk/CHANGES.txt
U zope.publisher/trunk/src/zope/publisher/browser.py
U zope.publisher/trunk/src/zope/publisher/configure.zcml
U zope.publisher/trunk/src/zope/publisher/interfaces/browser.py
U zope.publisher/trunk/src/zope/publisher/tests/test_baserequest.py
-=-
Modified: zope.publisher/trunk/CHANGES.txt
===================================================================
--- zope.publisher/trunk/CHANGES.txt 2009-03-05 00:40:18 UTC (rev 97504)
+++ zope.publisher/trunk/CHANGES.txt 2009-03-05 00:47:39 UTC (rev 97505)
@@ -4,6 +4,28 @@
3.5.7dev (unreleased)
---------------------
+- Fix: ensure that we only apply skin interface in setDefaultSkin which also
+ provide IBrowserSkinType. This will ensure that we find a skin if the
+ applySkin method will lookup for a skin based on this type interface.
+
+- Fix: Make it possible to use adapters and not only interfaces as skins from
+ the adapter registry. Right now the defaultSkin directive registers simple
+ interfaces as skin adapters which will run into a TypeError if someone tries
+ to adapter such a skin adapter. Probably we should change the defaultSkin
+ directive and register real adapters instead of using the interfaces as fake
+ adapters where we expect adapter factories.
+
+- Feature: allow to use applySkin with different skin types using the optional
+ argument skinType which is by default set to IBrowserSkinType
+
+- Feature: implemented the default skin pattern within adapters. This allows
+ us to register default skins for other requests then only IBrowserRequest
+ using IDefaultSkin adapters.
+
+ Note, ISkinnable and ISkinType and the skin implementation should be moved
+ out of the browser request modules. Packages like z3c.jsonrpc do not depend
+ on IBrowserRequest but they are skinnable.
+
- Feature: added ISkinnable interface which allows us to implement the apply
skin pattern not only for IBrowserRequest
Modified: zope.publisher/trunk/src/zope/publisher/browser.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/browser.py 2009-03-05 00:40:18 UTC (rev 97504)
+++ zope.publisher/trunk/src/zope/publisher/browser.py 2009-03-05 00:47:39 UTC (rev 97505)
@@ -28,8 +28,10 @@
import tempfile
import zope.component
-from zope.interface import implements, directlyProvides
+import zope.interface
+from zope.interface import implements, directlyProvides, alsoProvides
from zope.interface import directlyProvidedBy, providedBy
+from zope.interface.interfaces import IInterface
from zope.i18n.interfaces import IUserPreferredLanguages
from zope.i18n.interfaces import IUserPreferredCharsets
from zope.location import Location
@@ -41,6 +43,7 @@
from zope.publisher.interfaces.browser import IBrowserApplicationRequest
from zope.publisher.interfaces.browser import IBrowserView
from zope.publisher.interfaces.browser import IBrowserPage
+from zope.publisher.interfaces.browser import ISkinType
from zope.publisher.interfaces.browser import IBrowserSkinType
from zope.publisher.interfaces.browser import ISkinChangedEvent
from zope.publisher.interfaces.http import IHTTPRequest
@@ -907,15 +910,42 @@
raise NotImplementedError("Subclasses should override __call__ to "
"provide a response body")
+
+def getDefaultSkin(request):
+ """Returns the IDefaultSkin layer for IBrowserRequest."""
+ return IDefaultBrowserLayer
+
+
def setDefaultSkin(request):
"""Sets the default skin for the request.
The default skin is a marker interface that can be registered as an
- adapter that provides IDefaultSkin for the request type.
+ adapter that provides IDefaultSkin for the request type. A default skin
+ interface like any other skin must also provide IBrowserSkinType. This is
+ important since applySkin will lookup for skins based on this type.
- If a default skin is not available, the default layer
- (IDefaultBrowserLayer) is used.
+ Note: Any interfaces that are directly provided by the request coming into
+ this method are replaced by the applied layer/skin interface. This is very
+ important since the retry pattern can use a clean request without any
+ directly provided interface.
+ If a default skin is not available, the fallback default skin get applied
+ if available for the given request type. The default fallback skin is
+ implemented as an named adapter factory providing IDefaultSkin and
+ using ``default`` as name.
+
+ Important to know is that some skin adapters get registered as interfaces
+ and the fallback skins as adapters. See the defaultSkin directive in
+ zope.app.publication.zcml for more information which registers plain
+ interfaces as adapters which are not adaptable. (issue?)
+
+ Each request can only have one (unnamed) default skin and will fallback to
+ the named (default) fallback skin if available.
+
+ Only the IBrowserRequest provides such a default fallback adapter. This
+ adapter will apply the IDefaultBrowserLayer if no explicit default skin
+ is registered.
+
To illustrate, we'll first use setDefaultSkin without a registered
IDefaultSkin adapter:
@@ -926,11 +956,33 @@
>>> IDefaultBrowserLayer.providedBy(request)
False
+ If we try to set a default skin and no one exist we will not fail but
+ nothing happens
+
>>> setDefaultSkin(request)
+
+ Make sure our IDefaultBrowserLayer provides the IBrowserSkinType interface.
+ This is done in the configure.zcml using the interface directive:
+
+ >>> IBrowserSkinType.providedBy(IDefaultBrowserLayer)
+ False
+
+ >>> alsoProvides(IDefaultBrowserLayer, IBrowserSkinType)
+ >>> IBrowserSkinType.providedBy(IDefaultBrowserLayer)
+ True
+
+ The getDefaultSkin provides an adapter providing IDefaultSkin which we
+ register as named adapter using ``default`` as name:
+
+ >>> zope.component.provideAdapter(getDefaultSkin,
+ ... (IBrowserRequest,), IDefaultSkin, name='default')
+
+ >>> setDefaultSkin(request)
>>> IDefaultBrowserLayer.providedBy(request)
True
- When we register a default layer, however:
+ When we register a default layer, wihtout that the skin provides an
+ ISkinType the skin doesn't get applied:
>>> from zope.interface import Interface
>>> class IMySkin(Interface):
@@ -938,12 +990,24 @@
>>> zope.component.provideAdapter(IMySkin, (IBrowserRequest,),
... IDefaultSkin)
- setDefaultSkin uses the layer instead of IDefaultBrowserLayer.providedBy:
+ >>> setDefaultSkin(request)
+ >>> IMySkin.providedBy(request)
+ False
+ >>> IDefaultBrowserLayer.providedBy(request)
+ True
+ The default skin must provide IBrowserSkinType:
+
+ >>> alsoProvides(IMySkin, IBrowserSkinType)
+ >>> IBrowserSkinType.providedBy(IMySkin)
+ True
+
+ setDefaultSkin uses the layer instead of IDefaultBrowserLayer:
+
>>> request = Request()
>>> IMySkin.providedBy(request)
False
- >>> IDefaultSkin.providedBy(request)
+ >>> IDefaultBrowserLayer.providedBy(request)
False
>>> setDefaultSkin(request)
@@ -954,7 +1018,8 @@
False
Any interfaces that are directly provided by the request coming into this
- method are replaced by the applied layer/skin interface:
+ method are replaced by the applied layer/skin interface. This is important
+ for our retry pattern which will ensure that we start with a clean request:
>>> request = Request()
>>> class IFoo(Interface):
@@ -969,12 +1034,24 @@
"""
adapters = zope.component.getSiteManager().adapters
skin = adapters.lookup((providedBy(request),), IDefaultSkin, '')
+ if skin is None:
+ # find a named ``default`` adapter providing IDefaultSkin as fallback
+ skin = adapters.lookup((providedBy(request),), IDefaultSkin,
+ 'default')
if skin is not None:
- directlyProvides(request, skin)
- else:
- directlyProvides(request, IDefaultBrowserLayer)
+ try:
+ # the default fallback skin is registered as a named adapter
+ skin = skin(request)
+ except TypeError, e:
+ # the defaultSkin directive registers skins as interfaces and not
+ # as adapters (issue?)
+ pass
+ if ISkinType.providedBy(skin):
+ # silently ignore skins which do not provide ISkinType
+ directlyProvides(request, skin)
-def applySkin(request, skin):
+
+def applySkin(request, skin, skinType=IBrowserSkinType):
"""Change the presentation skin for this request.
>>> import pprint
@@ -1016,9 +1093,10 @@
>>> cleanUp()
"""
- # Remove all existing skin declarations (commonly the default skin).
+ # Remove all existing skin declarations (commonly the default skin) based
+ # on the given skin type.
ifaces = [iface for iface in directlyProvidedBy(request)
- if not IBrowserSkinType.providedBy(iface)]
+ if not skinType.providedBy(iface)]
# Add the new skin.
ifaces.append(skin)
directlyProvides(request, *ifaces)
Modified: zope.publisher/trunk/src/zope/publisher/configure.zcml
===================================================================
--- zope.publisher/trunk/src/zope/publisher/configure.zcml 2009-03-05 00:40:18 UTC (rev 97504)
+++ zope.publisher/trunk/src/zope/publisher/configure.zcml 2009-03-05 00:47:39 UTC (rev 97505)
@@ -6,6 +6,11 @@
<interface interface="zope.publisher.interfaces.browser.IBrowserSkinType" />
<interface interface="zope.publisher.interfaces.xmlrpc.IXMLRPCRequest" />
+
+ <interface
+ interface="zope.publisher.interfaces.browser.IDefaultBrowserLayer"
+ type="zope.publisher.interfaces.browser.IBrowserSkinType"
+ />
<class class="xmlrpclib.Binary">
<allow attributes="data encode decode" />
@@ -19,6 +24,13 @@
<adapter factory=".xmlrpc.PythonDateTimePreMarshaller" />
<adapter factory=".xmlrpc.DictPreMarshaller" />
+ <adapter
+ name="default"
+ factory=".browser.getDefaultSkin"
+ for="zope.publisher.interfaces.browser.IBrowserRequest"
+ provides="zope.publisher.interfaces.browser.IDefaultSkin"
+ />
+
<apidoc:bookchapter
zcml:condition="have apidoc"
id="zopepublisherhttpresults.txt"
Modified: zope.publisher/trunk/src/zope/publisher/interfaces/browser.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/interfaces/browser.py 2009-03-05 00:40:18 UTC (rev 97504)
+++ zope.publisher/trunk/src/zope/publisher/interfaces/browser.py 2009-03-05 00:47:39 UTC (rev 97505)
@@ -18,7 +18,7 @@
__docformat__ = "reStructuredText"
-from zope.interface import Interface, Attribute, directlyProvides
+from zope.interface import Interface, Attribute, directlyProvides, alsoProvides
from zope.interface.interfaces import IInterface
from zope.component.interfaces import IView
@@ -140,5 +140,8 @@
class IDefaultBrowserLayer(IBrowserRequest):
"""The default layer."""
-class IBrowserSkinType(IInterface):
+class ISkinType(IInterface):
+ """Base interface for skin types."""
+
+class IBrowserSkinType(ISkinType):
"""A skin is a set of layers."""
Modified: zope.publisher/trunk/src/zope/publisher/tests/test_baserequest.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/tests/test_baserequest.py 2009-03-05 00:40:18 UTC (rev 97504)
+++ zope.publisher/trunk/src/zope/publisher/tests/test_baserequest.py 2009-03-05 00:47:39 UTC (rev 97505)
@@ -94,13 +94,16 @@
def test_retry_keeps_everything(self):
"""lowlevel test for retry (see #98440)"""
from zope.publisher.browser import TestRequest, setDefaultSkin
- from zope.publisher.interfaces.browser import IDefaultSkin, IBrowserRequest
+ from zope.publisher.interfaces.browser import IDefaultSkin
+ from zope.publisher.interfaces.browser import IBrowserRequest
+ from zope.publisher.interfaces.browser import IBrowserSkinType
# create a retryable request
request = TestRequest()
self.assertTrue(request.supportsRetry())
# create a skin and register it as the default skin
class ISomeSkin(Interface):
pass
+ alsoProvides(ISomeSkin, IBrowserSkinType)
provideAdapter(ISomeSkin, (IBrowserRequest,), IDefaultSkin)
# set the default skin for the request
setDefaultSkin(request)
More information about the Checkins
mailing list