[Checkins] SVN: zope.publisher/trunk/ fix QUERY_STRING-during-POST handling for Py 2.6; make setDefaultSkin more friendly to interface default skins; prepare for release.

Gary Poster gary.poster at canonical.com
Thu Oct 22 14:59:51 EDT 2009


Log message for revision 105224:
  fix QUERY_STRING-during-POST handling for Py 2.6; make setDefaultSkin more friendly to interface default skins; prepare for release.

Changed:
  U   zope.publisher/trunk/CHANGES.txt
  U   zope.publisher/trunk/setup.py
  U   zope.publisher/trunk/src/zope/publisher/browser.py
  U   zope.publisher/trunk/src/zope/publisher/skinnable.py
  U   zope.publisher/trunk/src/zope/publisher/skinnable.txt
  U   zope.publisher/trunk/src/zope/publisher/tests/test_browserrequest.py

-=-
Modified: zope.publisher/trunk/CHANGES.txt
===================================================================
--- zope.publisher/trunk/CHANGES.txt	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/CHANGES.txt	2009-10-22 18:59:50 UTC (rev 105224)
@@ -1,13 +1,20 @@
 CHANGES
 =======
 
-3.10.0 (unreleased)
+3.10.0 (2009-10-22)
 -------------------
 
 - Moved the implementation of zope.publisher.contenttype to
   zope.contenttype.parse, leaving BBB imports and moving tests along.
   zope.contenttype is a new but light-weight dependency of this package.
 
+- Supported Python 2.6 by keeping QUERY_STRING out of request.form if
+  the method is a POST.  The original QUERY_STRING is still available if
+  further processing is needed.
+
+- Better supported the zcml ``defaultSkin`` directive's behavior (registering
+  an interface as a default skin) in the ``setDefaultSkin`` function.
+
 3.9.3 (2009-10-08)
 ------------------
 
@@ -37,7 +44,7 @@
 
 - Some parts of zope.app.publisher packages was moved into this package
   during zope.app.publisher refactoring:
-  
+
    * IModifiableUserPreferredLanguages adapter for requests
    * browser:defaultView and browser:defaultSkin ZCML directives
    * IHTTPView, IXMLRPCView and like interfaces
@@ -104,7 +111,7 @@
 
 - Add an adapter from ``zope.security.interfaces.IPrincipal`` to
   ``zope.publisher.interfaces.logginginfo.ILoggingInfo``. It was moved
-  from ``zope.app.security`` as a part of refactoring process. 
+  from ``zope.app.security`` as a part of refactoring process.
 
 - Add adapters from HTTP and FTP request to
   ``zope.authentication.ILoginPassword`` interface. They are moved from
@@ -146,7 +153,7 @@
 - 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.

Modified: zope.publisher/trunk/setup.py
===================================================================
--- zope.publisher/trunk/setup.py	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/setup.py	2009-10-22 18:59:50 UTC (rev 105224)
@@ -28,7 +28,7 @@
 """
 
 setup(name='zope.publisher',
-      version = '3.10.0dev',
+      version = '3.10.0',
       url='http://pypi.python.org/pypi/zope.publisher',
       license='ZPL 2.1',
       author='Zope Corporation and Contributors',

Modified: zope.publisher/trunk/src/zope/publisher/browser.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/browser.py	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/src/zope/publisher/browser.py	2009-10-22 18:59:50 UTC (rev 105224)
@@ -285,7 +285,15 @@
         if 'QUERY_STRING' not in self._environ:
             self._environ['QUERY_STRING'] = ''
 
-        fs = ZopeFieldStorage(fp=fp, environ=self._environ,
+        # The Python 2.6 cgi module mixes the query string and POST values
+        # together.  We do not want this.
+        env = self._environ
+        if self.method == 'POST' and self._environ['QUERY_STRING']:
+            env = env.copy()
+            del env['QUERY_STRING']
+
+
+        fs = ZopeFieldStorage(fp=fp, environ=env,
                               keep_blank_values=1)
 
         fslist = getattr(fs, 'list', None)

Modified: zope.publisher/trunk/src/zope/publisher/skinnable.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/skinnable.py	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/src/zope/publisher/skinnable.py	2009-10-22 18:59:50 UTC (rev 105224)
@@ -24,6 +24,7 @@
 
 import zope.component
 import zope.interface
+import zope.interface.interfaces
 
 from zope.publisher import interfaces
 
@@ -48,27 +49,28 @@
     skin = adapters.lookup((zope.interface.providedBy(request),),
         interfaces.IDefaultSkin, '')
     if skin is None:
-        # find a named ``default`` adapter providing IDefaultSkin as fallback
+        # Find a named ``default`` adapter providing IDefaultSkin as fallback.
         skin = adapters.lookup((zope.interface.providedBy(request),),
             interfaces.IDefaultSkin, 'default')
         if skin is None:
             # Let's be nice and continue to work for IBrowserRequest's
-            # without relying on adapter registrations
+            # without relying on adapter registrations.
             if interfaces.browser.IBrowserRequest.providedBy(request):
                 skin = getDefaultSkin
     if skin is not None:
-        try:
-            # the default fallback skin is registered as a named adapter
+        if not zope.interface.interfaces.IInterface.providedBy(skin):
+            # 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?)
+        else:
+            # The defaultSkin directive registers skins as interfaces and not
+            # as adapters.  We will not try to adapt the request to an
+            # interface to produce an interface.
             pass
         if interfaces.ISkinType.providedBy(skin):
             # silently ignore skins which do not provide ISkinType
             zope.interface.directlyProvides(request, skin)
         else:
-            raise TypeError("Skin interface %s doesn't provide ISkinType" % 
+            raise TypeError("Skin interface %s doesn't provide ISkinType" %
                 skin)
 
 

Modified: zope.publisher/trunk/src/zope/publisher/skinnable.txt
===================================================================
--- zope.publisher/trunk/src/zope/publisher/skinnable.txt	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/src/zope/publisher/skinnable.txt	2009-10-22 18:59:50 UTC (rev 105224)
@@ -2,64 +2,68 @@
 Skinnable
 =========
 
-Request can provide skins. But what's exactly a skin. At the code level, a skin
-is just an interface which a request provides. Why do we need skins? We can use
-skins for register different adapter.
+Requests can provide skins. But what exactly is a skin? At the code
+level, a skin is just an interface which a request provides. Why do we
+need skins? We can use skins for registering different adapters.
 
-That's a little bit much use of the word skin. Let's explain it mor detailed.
-A skin is an interface which provides a type interface. This type interface 
-is called ISkinType. The zope.publisher right now provides only one specific
-skin type interface used in the IBrowserRequest implementation. This interface
-is called BrowserSkinType.
+That's a little bit much use of the word skin. Let's explain it in more
+detail. A skin is an interface which provides an interface. This
+interface is called ISkinType. The zope.publisher right now provides
+only one specific skin type interface used in the IBrowserRequest
+implementation. This interface is called BrowserSkinType.
 
-Since the zope server provides request factories for biuld a request, each
-such request type could provide it's own skin type interface. This ensures that
-we can register a skin type for each request.
+Since the zope server provides request factories for building a request,
+each such request type could provide it's own skin type interface. This
+ensures that we can register a skin type for each request.
 
-Now a more high level point of view. A skin is a concept which we can use for
-provide different kind of views, templates or other adapter adapting a request.
-This skins are the key component for provide different kind of application
-layers. Then a skin makes it possible that an application can act very
-different with each skin. Of corse that's only the case at the interaction
-level where the request is involved. But that's moste the time the case since
-we have an web application server. 
+Now let's look at a higher level. A skin is a concept which we can use
+for providing different kinds of views, templates or other adapters
+adapting a request. These skins are the key component for providing
+different kind of application layers. A skin makes it possible for
+an application to act very differently with each skin. Of course, that's
+only the case at the interaction level where the request is involved.
+But that's the case most of the time since we have a web application
+server.
 
-Another part of the skinnable concept is that a skin can define a default skin.
-This is done within the IDefaultSkin interface. Such a default skin get defined
-at the level request implementation level. Such a default skin can get overriden
-in a custom setup. Overriding a skin can be done by using the defaultSkin
-directive offeren from zope.app.publication.zcml.
+Another part of the skinnable concept is that an application can define
+zero or more default skins. This is done with the IDefaultSkin
+interface. Default skins can be defined for request interfaces or
+implementations. Such a default skin can get overriden in a custom
+setup. Overriding a skin can be done by using the defaultSkin directive
+offered from zope.app.publication.zcml.
 
-Why does a request need a default skin. If a request needs to provide some
-pluggable concepts which requires that a default adapter is registered for
-a request, this adapter could be registered for the default skin. If a project
-likes to use another pattern and needs to register another request adapter, the
-project could register it's own skin and register the custom adapter for this
-new project based skin. This is very handy and allows to skip a complete
-default skin based setup for a given request.
+Why does a request need a default skin? If a request needs to provide
+some pluggable concepts that require that a default adapter is
+registered for a request, this adapter could be registered for the
+default skin. If a project likes to use another pattern and needs to
+register another request adapter, the project could register its own
+skin and register the custom adapter for this new project based skin.
+This is very handy and allows developers to skip a complete
+default-skin-based setup for a given request.
 
-In general this means a request interface and the request class wich implements
-the request interface does only provide the basic API but no adapters if the
-request needs to delegate things to an adapter. For such a request a default
-skin can get defined. This default skin can provide all adatpers which the
-request implementation needs to have. This gives us to option to replace the
-default skin within an own skin and provide custom adapters.
+In general, this means a request interface and the request class that
+implements the request interface only provides the basic API but no
+adapters if the request needs to delegate things to an adapter. For such
+a request a default skin can get defined. This default skin can provide
+all adapters which the request implementation needs to have. This gives
+us the option to replace the default skin within a custom skin and
+provide custom adapters.
 
-Our exmple will define a full request and all it's component from scratch.
+Our exmple will define a full request and all its components from scratch.
 it doesn't depend on IBrowserRequest. We'll use a JSON-RPC as sample like
 the z3c.jsonrpc package provides.
 
 Layers and Skins
 ----------------
 
-We also use the term layer if we talk about skins. A layer or skin layer is an
-interface registered as a ISkinType without a name. Zope provides a traversal
-pattern which allows to traverse a skin within a skin namespace called
-``skin``. This allows to traverse to traverse to a method called applySkin
-which will aplly a registered named skin. this means if we register a ISkinType
-as within an optional name argument, we will register a skin. if we register a
-ISkinType without a name just we register a layer. This means, layers are not
-traversable ISkinType interfaces.
+We also use the term "layer" if we talk about skins. A layer or skin
+layer is an interface registered as a ISkinType without a name. Zope
+provides a traversal pattern which allows traversal to a skin within a
+skin namespace called ``skin``. This allows traversal to a method called
+``applySkin`` which will apply a registered named skin. This means if we
+register an ISkinType with a name argument, we will register a skin. if
+we register a ISkinType without a name just we register a layer. This
+means, layers are not traversable ISkinType interfaces.
 
 Let's start define a request:
 
@@ -101,17 +105,18 @@
 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 after a retry get started.
+directly provided interface after a retry gets started.
 
-If a default skin is not available, the fallback default skin get applied
+If a default skin is not available, the fallback default skin is 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. 
+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?)
+and the fallback skins as adapters. See the defaultSkin directive in
+zope.app.publication.zcml for more information.  It registers plain
+interfaces as adapters which are not adaptable.  We have special code to
+handle this case, which we will demonstrate below.
 
 Each request can only have one (unnamed) default skin and will fallback to
 the named (default) fallback skin if available.
@@ -148,11 +153,32 @@
   >>> ISkinType.providedBy(IJSONDefaultLayer)
   True
 
-Let's define a default skin adatper which the setDefaulSkin can use. This
-adapter return our IJSONDefaultLayer. We also register this adapter within 
+Now let's examine what can happen with our legacy case: an interface is
+registered as an adapter.
+
+  >>> from zope.publisher.interfaces import IDefaultSkin
+  >>> sm = zope.component.getSiteManager()
+  >>> sm.registerAdapter(
+  ...     IJSONDefaultLayer, (IJSONRequest,), IDefaultSkin, name='default')
+  >>> request = JSONRequest(StringIO(''), {})
+  >>> IJSONDefaultLayer.providedBy(request)
+  False
+  >>> setDefaultSkin(request)
+  >>> IJSONDefaultLayer.providedBy(request)
+  True
+
+What if the request already provides the interface?
+
+  >>> IJSONDefaultLayer.providedBy(request)
+  True
+  >>> setDefaultSkin(request)
+  >>> IJSONDefaultLayer.providedBy(request)
+  True
+
+Now let's define a default skin adapter which the setDefaultSkin can use. This
+adapter return our IJSONDefaultLayer. We also register this adapter within
 ``default`` as name:
 
-  >>> from zope.publisher.interfaces import IDefaultSkin
   >>> def getDefaultJSONLayer(request):
   ...     return IJSONDefaultLayer
 

Modified: zope.publisher/trunk/src/zope/publisher/tests/test_browserrequest.py
===================================================================
--- zope.publisher/trunk/src/zope/publisher/tests/test_browserrequest.py	2009-10-22 18:38:23 UTC (rev 105223)
+++ zope.publisher/trunk/src/zope/publisher/tests/test_browserrequest.py	2009-10-22 18:59:50 UTC (rev 105224)
@@ -181,7 +181,7 @@
 
         """Produce a Fieldstorage with a name wich is None, this
         should be catched"""
-        
+
         extra = {'REQUEST_METHOD':'POST',
                  'PATH_INFO': u'/',
                  'CONTENT_TYPE': 'multipart/form-data;\
@@ -204,7 +204,7 @@
                  'PATH_INFO': u'/',
                  'CONTENT_TYPE': 'multipart/form-data;\
                  boundary=---------------------------1'}
-        
+
         request  = self._createRequest(extra, body=LARGE_FILE_BODY)
         request.processInputs()
         self.assert_(request.form['upload'].name)
@@ -280,6 +280,14 @@
         publish(request)
         self.assertEqual(request.form, {u'a':[u'5',u'6'], u'b':u'1'})
 
+    def testQueryStringIgnoredForPOST(self):
+        request = self._createRequest(
+            {"REQUEST_METHOD": "POST",
+             'PATH_INFO': '/folder/item3'}, body='c=5&d:int=6')
+        publish(request)
+        self.assertEqual(request.form, {u'c': u'5', u'd': 6})
+        self.assertEqual(request.get('QUERY_STRING'), 'a=5&b:int=6')
+
     def testFormTupleTypes(self):
         extra = {'QUERY_STRING':'a:tuple=5&a:tuple=6&b=1'}
         request = self._createRequest(extra)



More information about the checkins mailing list