[Checkins] SVN: ZPublisherEventsBackport/trunk/s ZPublisher events for Zope 2.10

Laurence Rowe l at lrowe.co.uk
Fri Oct 23 07:10:59 EDT 2009


Log message for revision 105240:
  ZPublisher events for Zope 2.10

Changed:
  A   ZPublisherEventsBackport/trunk/setup.py
  A   ZPublisherEventsBackport/trunk/src/
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/__init__.py
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/configure.zcml
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/interfaces.py
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/patch.py
  A   ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/pubevents.py

-=-
Added: ZPublisherEventsBackport/trunk/setup.py
===================================================================
--- ZPublisherEventsBackport/trunk/setup.py	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/setup.py	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,30 @@
+from setuptools import setup, find_packages
+import os.path
+
+version = '1.0'
+
+setup(
+    name='ZPublisherEventsBackport',
+    version=version,
+    description="Backport publication events from Zope 2.12 ZPublisher to Zope 2.10",
+    classifiers=[
+        "Programming Language :: Python",
+        "Environment :: Web Environment",
+        "Framework :: Zope2",
+        "Intended Audience :: Developers",
+        "License :: OSI Approved :: Zope Public License",
+        "Topic :: Software Development :: Libraries :: Python Modules",
+        ],
+    keywords='',
+    url='',
+    author='Laurence Rowe',
+    author_email='laurence at lrowe.co.uk',
+    license='ZPL',
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    include_package_data=True,
+    zip_safe=False,
+    install_requires=[
+        ],
+    )
+

Added: ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/__init__.py
===================================================================
--- ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/__init__.py	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/__init__.py	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,19 @@
+try:
+    import ZPublisher.interfaces
+except ImportError:
+    import logging
+    import sys
+    import ZPublisher
+    import ZPublisher.Publish
+    from ZPublisherEventsBackport import interfaces
+    sys.modules['ZPublisher.interfaces'] = interfaces
+    ZPublisher.interfaces = interfaces
+    for name, iface in interfaces.__dict__.items():
+        if name.startswith('IPub'):
+            iface.__module__ = 'ZPublisher.interfaces'
+            iface.__identifier__ = "%s.%s" % (iface.__module__, iface.__name__)
+            iface.changed(None)
+    
+    from ZPublisherEventsBackport import patch
+    ZPublisher.Publish.publish=patch.publish
+    logging.info("Monkeypatch ZPublisher publish with publication events")

Added: ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/configure.zcml
===================================================================
--- ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/configure.zcml	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/configure.zcml	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,3 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+    <!-- Stub so configure phase may trigger patch -->
+</configure>

Copied: ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/interfaces.py (from rev 105239, Zope/branches/2.12/src/ZPublisher/interfaces.py)
===================================================================
--- ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/interfaces.py	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/interfaces.py	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,45 @@
+from zope.interface import Interface, Attribute
+
+#############################################################################
+# Publication events
+#  These are events notified in 'ZPublisher.Publish.publish'.
+
+class IPubEvent(Interface):
+    '''Base class for publication events.
+
+    Publication events are notified in 'ZPublisher.Publish.publish' to
+    inform about publications (aka requests) and their fate.
+    '''
+    request = Attribute('The request being affected')
+
+class IPubStart(IPubEvent):
+    '''Event notified at the beginning of 'ZPublisher.Publish.publish'.'''
+
+class IPubEnd(IPubEvent):
+    '''Event notified after request processing.
+
+    Note that a retried request ends before the retrial, the retrial
+    itself is considered a new event.
+    '''
+
+class IPubSuccess(IPubEnd):
+    '''A successful request processing.'''
+
+class IPubFailure(IPubEnd):
+    '''A failed request processing.
+
+    Note: If a subscriber to 'IPubSuccess' raises an exception,
+    then 'IPubFailure' may be notified in addtion to 'IPubSuccess'.
+    '''
+    exc_info = Attribute('''The exception info as returned by 'sys.exc_info()'.''')
+    retry = Attribute('Whether the request will be retried')
+
+
+class IPubAfterTraversal(IPubEvent):
+    """notified after traversal and an (optional) authentication."""
+
+
+class IPubBeforeCommit(IPubEvent):
+    """notified immediately before the transaction commit (i.e. after the main
+    request processing is finished.
+    """

Copied: ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/patch.py (from rev 105239, Zope/branches/2.12/src/ZPublisher/Publish.py)
===================================================================
--- ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/patch.py	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/patch.py	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,157 @@
+import logging
+import sys
+from ZPublisher.Publish import call_object
+from ZPublisher.Publish import missing_name
+from ZPublisher.Publish import dont_publish_class
+from ZPublisher.Publish import get_module_info
+from ZPublisher.Publish import Retry
+from ZPublisher.mapply import mapply
+from zExceptions import Redirect
+# XXX change from ZPublisher 2.12
+# from zope.publisher.interfaces import ISkinnable
+from zope.publisher.browser import setDefaultSkin
+from zope.security.management import newInteraction, endInteraction
+from zope.event import notify
+
+from pubevents import PubStart, PubSuccess, PubFailure, \
+     PubBeforeCommit, PubAfterTraversal
+
+
+def publish(request, module_name, after_list, debug=0,
+            # Optimize:
+            call_object=call_object,
+            missing_name=missing_name,
+            dont_publish_class=dont_publish_class,
+            mapply=mapply,
+            ):
+
+    (bobo_before, bobo_after, object, realm, debug_mode, err_hook,
+     validated_hook, transactions_manager)= get_module_info(module_name)
+
+    parents=None
+    response=None
+
+    try:
+        notify(PubStart(request))
+        # TODO pass request here once BaseRequest implements IParticipation
+        newInteraction()
+
+        request.processInputs()
+
+        request_get=request.get
+        response=request.response
+
+        # First check for "cancel" redirect:
+        if request_get('SUBMIT','').strip().lower()=='cancel':
+            cancel=request_get('CANCEL_ACTION','')
+            if cancel:
+                raise Redirect, cancel
+
+        after_list[0]=bobo_after
+        if debug_mode:
+            response.debug_mode=debug_mode
+        if realm and not request.get('REMOTE_USER',None):
+            response.realm=realm
+
+        if bobo_before is not None:
+            bobo_before()
+
+        # Get the path list.
+        # According to RFC1738 a trailing space in the path is valid.
+        path=request_get('PATH_INFO')
+
+        request['PARENTS']=parents=[object]
+
+        if transactions_manager:
+            transactions_manager.begin()
+
+        object=request.traverse(path, validated_hook=validated_hook)
+
+        notify(PubAfterTraversal(request))
+
+        if transactions_manager:
+            transactions_manager.recordMetaData(object, request)
+
+        result=mapply(object, request.args, request,
+                      call_object,1,
+                      missing_name,
+                      dont_publish_class,
+                      request, bind=1)
+
+        if result is not response:
+            response.setBody(result)
+
+        notify(PubBeforeCommit(request))
+
+        if transactions_manager:
+            transactions_manager.commit()
+        endInteraction()
+
+        notify(PubSuccess(request))
+
+        return response
+    except:
+        # save in order to give 'PubFailure' the original exception info
+        exc_info = sys.exc_info()
+        # DM: provide nicer error message for FTP
+        sm = None
+        if response is not None:
+            sm = getattr(response, "setMessage", None)
+
+        if sm is not None:
+            from asyncore import compact_traceback
+            cl,val= sys.exc_info()[:2]
+            sm('%s: %s %s' % (
+                getattr(cl,'__name__',cl), val,
+                debug_mode and compact_traceback()[-1] or ''))
+
+        if err_hook is not None:
+            retry = False
+            if parents:
+                parents=parents[0]
+            try:
+                try:
+                    return err_hook(parents, request,
+                                    sys.exc_info()[0],
+                                    sys.exc_info()[1],
+                                    sys.exc_info()[2],
+                                    )
+                except Retry:
+                    if not request.supports_retry():
+                        return err_hook(parents, request,
+                                        sys.exc_info()[0],
+                                        sys.exc_info()[1],
+                                        sys.exc_info()[2],
+                                        )
+                    retry = True
+            finally:
+                # Note: 'abort's can fail. Nevertheless, we want end request handling
+                try: 
+                    if transactions_manager:
+                        transactions_manager.abort()
+                finally:
+                    endInteraction()
+                    notify(PubFailure(request, exc_info, retry))
+
+            # Only reachable if Retry is raised and request supports retry.
+            newrequest=request.retry()
+            request.close()  # Free resources held by the request.
+
+            # Set the default layer/skin on the newly generated request
+            # XXX change from ZPublisher 2.12
+            # if ISkinnable.providedBy(newrequest):
+            setDefaultSkin(newrequest)
+            try:
+                return publish(newrequest, module_name, after_list, debug)
+            finally:
+                newrequest.close()
+
+        else:
+            # Note: 'abort's can fail. Nevertheless, we want end request handling
+            try:
+                if transactions_manager:
+                    transactions_manager.abort()
+            finally:
+                endInteraction()
+                notify(PubFailure(request, exc_info, False))
+            raise

Copied: ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/pubevents.py (from rev 105239, Zope/branches/2.12/src/ZPublisher/pubevents.py)
===================================================================
--- ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/pubevents.py	                        (rev 0)
+++ ZPublisherEventsBackport/trunk/src/ZPublisherEventsBackport/pubevents.py	2009-10-23 11:10:58 UTC (rev 105240)
@@ -0,0 +1,44 @@
+'''Publication events.
+
+They are notified in 'ZPublisher.Publish.publish' and 
+inform about publications and their fate.
+
+Subscriptions can be used for all kinds of request supervision,
+e.g. request and error rate determination, writing high resolution logfiles
+for detailed time related analysis, inline request monitoring.
+'''
+from zope.interface import implements
+
+from interfaces import IPubStart, IPubSuccess, IPubFailure, \
+     IPubAfterTraversal, IPubBeforeCommit
+
+class _Base(object):
+    """PubEvent base class."""
+
+    def __init__(self, request):
+        self.request = request
+
+class PubStart(_Base):
+    '''notified at the beginning of 'ZPublisher.Publish.publish'.'''
+    implements(IPubStart)
+
+class PubSuccess(_Base):
+    '''notified at successful request end.'''
+    implements(IPubSuccess)
+
+class PubFailure(object):
+    '''notified at failed request end.'''
+    implements(IPubFailure)
+
+    def __init__(self, request, exc_info, retry):
+        self.request, self.exc_info, self.retry = request, exc_info, retry
+
+
+class PubAfterTraversal(_Base):
+    """notified after traversal and an (optional) authentication."""
+    implements(IPubAfterTraversal)
+
+
+class PubBeforeCommit(_Base):
+    """notified immediately before the commit."""
+    implements(IPubBeforeCommit)



More information about the checkins mailing list