From reebalazs at codespeak.net Mon Dec 11 11:36:27 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Mon, 11 Dec 2006 11:36:27 +0100 (CET)
Subject: [KSS-checkins] r35561 - kukit/kss.core/trunk
Message-ID: <20061211103627.BBAC410063@code0.codespeak.net>
Author: reebalazs
Date: Mon Dec 11 11:36:24 2006
New Revision: 35561
Modified:
kukit/kss.core/trunk/azaxview.py
Log:
Start fixing the event acquisition and test issues (ongoing...)
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Mon Dec 11 11:36:24 2006
@@ -62,6 +62,7 @@
class SiteView(BrowserView):
"""A browser view that is its own site
"""
+ implements(ISite)
def __init__(self, context, request):
super(SiteView, self).__init__(context, request)
@@ -69,14 +70,15 @@
next_sitemanager = component.getSiteManager()
self._sitemanager = ViewSiteManager('siteview')
- interface.alsoProvides(self, ISite)
self._sitemanager.__bases__ = (next_sitemanager, )
# register object event handler
- self._sitemanager.registerHandler(self._eventRedispatcher)
- setHooks()
- setSite(self)
+ # we should wrap it in the acquisition context
+ wrapped_view = self.__of__(self.context)
+ self._sitemanager.registerHandler(wrapped_view._eventRedispatcher)
+ ##setHooks()
+ ##setSite(self)
def getSiteManager(self):
return self._sitemanager
@@ -87,10 +89,11 @@
@component.adapter(Interface)
def _eventRedispatcher(self, event):
if not IAzaxEvent.providedBy(event):
- notify(AzaxEvent(self, event))
+ azaxevent = AzaxEvent(self, event)
+ notify(azaxevent)
def render(self):
- clearSite()
+ pass #clearSite()
class AzaxBaseView(SiteView):
""" Base kss view
From reebalazs at codespeak.net Tue Dec 12 19:31:32 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 12 Dec 2006 19:31:32 +0100 (CET)
Subject: [KSS-checkins] r35639 - in kukit/kss.core/trunk: . tests
Message-ID: <20061212183132.72BD310093@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 12 19:31:28 2006
New Revision: 35639
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/azaxview.txt
kukit/kss.core/trunk/siteview.txt
kukit/kss.core/trunk/tests/base.py
kukit/kss.core/trunk/tests/configure-unittest.zcml
kukit/kss.core/trunk/tests/test_azaxview.py
Log:
Fix tests apart from azaxview.txt and siteview.txt
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Tue Dec 12 19:31:28 2006
@@ -73,9 +73,17 @@
self._sitemanager.__bases__ = (next_sitemanager, )
+ # On Five, we should wrap it in the acquisition context
+ # see, if self has aq_parent, it is done obligatoraly
+ try:
+ self.context.aq_parent
+ except AttributeError:
+ # Zope3 - No problem.
+ wrapped_view = self
+ else:
+ wrapped_view = self.__of__(self.context)
+
# register object event handler
- # we should wrap it in the acquisition context
- wrapped_view = self.__of__(self.context)
self._sitemanager.registerHandler(wrapped_view._eventRedispatcher)
##setHooks()
##setSite(self)
Modified: kukit/kss.core/trunk/azaxview.txt
==============================================================================
--- kukit/kss.core/trunk/azaxview.txt (original)
+++ kukit/kss.core/trunk/azaxview.txt Tue Dec 12 19:31:28 2006
@@ -17,16 +17,23 @@
>>> from kss.core.azaxview import AzaxBaseView
>>> from kss.core.interfaces import IAzaxEvent
- >>> from kss.core.tests.base import DebugTestRequest
+ >>> from kss.core.tests.base import IDebugRequest
>>> from zope import component
>>> from zope.lifecycleevent import ObjectModifiedEvent
>>> from zope.lifecycleevent.interfaces import IObjectModifiedEvent
>>> from zope.event import notify
>>> from zope.app.component.interfaces import ISite
+ >>> from zope.interface import directlyProvides, directlyProvidedBy
+ >>> from zope.publisher.browser import TestRequest
>>> from zope.app.folder import folder
>>> myfolder = folder.rootFolder()
+This will make the commands rendered as test-friendly structures.
+
+ >>> request = TestRequest()
+ >>> directlyProvides(request, directlyProvidedBy(request) + IDebugRequest)
+
Now we will write our custom.
>>> class SampleView(AzaxBaseView):
@@ -35,7 +42,6 @@
... self.handle(ObjectModifiedEvent(title))
... return self.render()
- >>> request = DebugTestRequest()
>>> view = SampleView(myfolder, request)
>>> view.add_page("some title")
[]
Modified: kukit/kss.core/trunk/siteview.txt
==============================================================================
--- kukit/kss.core/trunk/siteview.txt (original)
+++ kukit/kss.core/trunk/siteview.txt Tue Dec 12 19:31:28 2006
@@ -21,6 +21,7 @@
When created this view will make it's manager the default site manager.
+Context must be
>>> from zope import component
>>> old_sitemanager = component.getSiteManager()
>>> view = SiteView(None, None)
Modified: kukit/kss.core/trunk/tests/base.py
==============================================================================
--- kukit/kss.core/trunk/tests/base.py (original)
+++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 19:31:28 2006
@@ -22,15 +22,12 @@
from Testing.ZopeTestCase import ZopeTestCase
import kss.core
from kss.core import AzaxBaseView
-#from kss.core import config
-#from ZPublisher.HTTPRequest import HTTPRequest
-#from cStringIO import StringIO
-#from Globals import InitializeClass
from OFS.SimpleItem import SimpleItem
from textwrap import dedent
from zope.publisher.browser import TestRequest
from zope.publisher.interfaces.browser import IBrowserRequest
from zope.interface import Interface, implements
+from zope import interface as iapi
try:
# Zope > 2.8
@@ -39,47 +36,24 @@
# Zope == 2.8
from zope.app.tests import placelesssetup
+# Test view
+#
+
+class TestView(AzaxBaseView):
+ def testMethod(self):
+ 'Yes.'
+
# Debug request
# This has a modified render.
class IDebugRequest(IBrowserRequest):
'The debug request'
-class DebugTestRequest(TestRequest):
- 'Debug test request'
- implements(IDebugRequest)
- def __init__(self):
- self.RESPONSE = DebugTestResponse()
- self.form = {}
-
-class DebugTestResponse:
- def __init__(self, status=200):
- self.status = status
- def getStatus(self):
- return self.status
- def setStatus(self, status):
- self.status = status
-
-# Fake content
-
-class FakeContent(SimpleItem, object):
- pass
-
-#InitializeClass(FakeContent)
-
class AzaxViewTestCase(ZopeTestCase):
def afterSetUp(self):
placelesssetup.setUp()
- # fake content
- fakecontent = FakeContent()
- self.folder._setObject('ob', fakecontent)
- fakecontent = fakecontent.__of__(self.folder)
- # Set up a fake view (with no content)
- fakerequest = TestRequest()
- debugfakerequest = DebugTestRequest()
- self.view = AzaxBaseView(fakecontent, fakerequest)
- self.debug_view = AzaxBaseView(fakecontent, debugfakerequest)
+
# Allow traversing
try:
import Products.Five
@@ -88,7 +62,7 @@
pass
# XXX TODO fix this?? --- never run yet on Z3
from zope.configuration.xmlconfig import XMLConfig
- XMLConfig('tests/configure-unittes.zcml', kss.core)()
+ XMLConfig('tests/configure-unittest.zcml', kss.core)()
else:
from Products.Five.zcml import load_string, load_config
load_config('meta.zcml', package=Products.Five)
@@ -122,7 +96,17 @@
load_config('meta.zcml', package=kss.core)
load_config('configure.zcml', package=kss.core)
load_config('configure-unittest.zcml', package=kss.core.tests)
-
+
+ def createView(self):
+ "Set up a fake view (with no content)"
+ self.view = self.folder.restrictedTraverse('testMethod')
+ return self.view
+
+ def setDebugRequest(self):
+ 'commands will be rendered as test friendly data structures'
+ request = self.portal.REQUEST
+ iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest)
+
def beforeTearDown(self):
placelesssetup.tearDown()
try:
Modified: kukit/kss.core/trunk/tests/configure-unittest.zcml
==============================================================================
--- kukit/kss.core/trunk/tests/configure-unittest.zcml (original)
+++ kukit/kss.core/trunk/tests/configure-unittest.zcml Tue Dec 12 19:31:28 2006
@@ -5,6 +5,7 @@
>
+
+
+
Modified: kukit/kss.core/trunk/tests/test_azaxview.py
==============================================================================
--- kukit/kss.core/trunk/tests/test_azaxview.py (original)
+++ kukit/kss.core/trunk/tests/test_azaxview.py Tue Dec 12 19:31:28 2006
@@ -22,7 +22,7 @@
import unittest, os
from textwrap import dedent
from zope.testing import doctest
-from base import AzaxViewTestCase, FakeContent, TestRequest, DebugTestRequest
+from base import AzaxViewTestCase
from kss.core import AzaxUnicodeError
from kss.core.plugins.core.interfaces import IKSSCoreCommands
from zope.testing.cleanup import CleanUp as PlacelessSetup
@@ -68,12 +68,12 @@
class TestAzaxView(AzaxViewTestCase):
def test_empty(self):
- view = self.view
+ view = self.createView()
commands = view.getCommands()
self.assertEqual(len(commands), 0)
def test_addCommand(self):
- view = self.view
+ view = self.createView()
commands = view.getCommands()
command = commands.addCommand('replaceInnerHTML', 'selector')
self.assertEqual(len(commands), 1)
@@ -86,7 +86,7 @@
# Nevertheless, we test all these cases
def _checkSetHtmlResult(self, content, content2=None):
- view = self.view
+ view = self.createView()
view.getCommandSet('core').replaceInnerHTML('div.class', content)
commands = view.getCommands()
self.assertEqual(len(commands), 1)
@@ -155,13 +155,13 @@
self.assertXMLEquals(a, self._wrapped_commands(b))
def test_empty(self):
- view = self.view
+ view = self.createView()
result = view.render()
- self.assertEquals(view.request.response.getHeader('Content-Type'), 'text/xml;charset=utf-8')
+ self.assertEquals(view.request.response.getHeader('content-type'), 'text/xml;charset=utf-8')
self.assertCommandsEqual(result, '')
def test_replaceInnerHTML(self):
- view = self.view
+ view = self.createView()
view.getCommandSet('core').replaceInnerHTML('div.class', 'new content')
result = view.render()
awaited = u'''\
@@ -173,7 +173,7 @@
self.assertCommandsEqual(result, awaited)
def test_setCommandSet(self):
- view = self.view
+ view = self.createView()
cs = view.getCommandSet('core')
cs.replaceInnerHTML('div.class', 'new content')
result = view.render()
From reebalazs at codespeak.net Tue Dec 12 20:18:36 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 12 Dec 2006 20:18:36 +0100 (CET)
Subject: [KSS-checkins] r35644 - kukit/kss.core/trunk/tests
Message-ID: <20061212191836.26A4C10086@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 12 20:18:34 2006
New Revision: 35644
Modified:
kukit/kss.core/trunk/tests/base.py
Log:
Separate loadCoreConfig method to be called from inherited tests
Modified: kukit/kss.core/trunk/tests/base.py
==============================================================================
--- kukit/kss.core/trunk/tests/base.py (original)
+++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 20:18:34 2006
@@ -53,7 +53,9 @@
def afterSetUp(self):
placelesssetup.setUp()
+ self.loadCoreConfig()
+ def loadCoreConfig(self, kss_core=True):
# Allow traversing
try:
import Products.Five
@@ -93,8 +95,9 @@
except IOError:
# Zope 2.10 / Five 1.3.6 does not have it
pass
- load_config('meta.zcml', package=kss.core)
- load_config('configure.zcml', package=kss.core)
+ if kss_core:
+ load_config('meta.zcml', package=kss.core)
+ load_config('configure.zcml', package=kss.core)
load_config('configure-unittest.zcml', package=kss.core.tests)
def createView(self):
From reebalazs at codespeak.net Tue Dec 12 21:44:51 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 12 Dec 2006 21:44:51 +0100 (CET)
Subject: [KSS-checkins] r35657 - kukit/kss.demo/trunk/tests
Message-ID: <20061212204451.2F7581008A@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 12 21:44:50 2006
New Revision: 35657
Modified:
kukit/kss.demo/trunk/tests/test_azaxview.py
Log:
Fix tests
Modified: kukit/kss.demo/trunk/tests/test_azaxview.py
==============================================================================
--- kukit/kss.demo/trunk/tests/test_azaxview.py (original)
+++ kukit/kss.demo/trunk/tests/test_azaxview.py Tue Dec 12 21:44:50 2006
@@ -21,29 +21,27 @@
import unittest, os
from zope.testing import doctest
from Testing.ZopeTestCase import ZopeTestCase
-from kss.core.tests.base import AzaxViewTestCase, FakeContent, \
- TestRequest, DebugTestRequest
+from kss.core.tests.base import AzaxViewTestCase
from kss.demo.azaxview import AzaxView
from Products.Five.zcml import load_string, load_config
import kss.demo
+try:
+ import Products.Five
+except AttributeError:
+ from kss.demo.simplecontent_z3 import SimpleContent
+else:
+ from kss.demo.simplecontent import SimpleContent
+
class AzaxDemoTestCase(AzaxViewTestCase):
def afterSetUp(self):
AzaxViewTestCase.afterSetUp(self)
load_config('meta.zcml', package=kss.demo)
load_config('configure.zcml', package=kss.demo)
- # fake content
- # XXX This is a holy mess. Go go macro adapters!
- fakecontent = FakeContent()
- self.folder._delObject('ob')
- self.folder._setObject('ob', fakecontent)
- fakecontent = fakecontent.__of__(self.folder)
- # Set up a fake view (with no content)
- # XXX commands will be rendered as data structures,
- # because we use DebugTestRequest instead of TestRequest.
- fakedebugrequest = DebugTestRequest()
- self.view = AzaxView(fakecontent, fakedebugrequest)
+ self.setDebugRequest()
+ self.folder._setObject('demo', SimpleContent('Demo', 'Demo'))
+ self.view = self.folder.demo.restrictedTraverse('getDivContent')
def test_instantiation(self):
view = self.view
From reebalazs at codespeak.net Tue Dec 12 21:45:31 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 12 Dec 2006 21:45:31 +0100 (CET)
Subject: [KSS-checkins] r35658 - kukit/kss.core/trunk/tests
Message-ID: <20061212204531.F38AE1008A@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 12 21:45:30 2006
New Revision: 35658
Modified:
kukit/kss.core/trunk/tests/base.py
Log:
Fix test, it is better to use self.portal.REQUEST
Modified: kukit/kss.core/trunk/tests/base.py
==============================================================================
--- kukit/kss.core/trunk/tests/base.py (original)
+++ kukit/kss.core/trunk/tests/base.py Tue Dec 12 21:45:30 2006
@@ -107,7 +107,7 @@
def setDebugRequest(self):
'commands will be rendered as test friendly data structures'
- request = self.portal.REQUEST
+ request = self.folder.REQUEST
iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest)
def beforeTearDown(self):
From jvloothuis at codespeak.net Sat Dec 16 00:01:37 2006
From: jvloothuis at codespeak.net (jvloothuis at codespeak.net)
Date: Sat, 16 Dec 2006 00:01:37 +0100 (CET)
Subject: [KSS-checkins] r35824 - in kukit/kss.core/trunk: . tests
Message-ID: <20061215230137.3DE731007C@code0.codespeak.net>
Author: jvloothuis
Date: Sat Dec 16 00:01:34 2006
New Revision: 35824
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/azaxview.txt
kukit/kss.core/trunk/tests/test_azaxview.py
Log:
Fixed a problem with the tests and the registration of the site manager, it now directly hooks into the component api instead of going through the previously disabled zope.app.component setSite stuff.
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 00:01:34 2006
@@ -41,17 +41,14 @@
from interfaces import IAzaxEvent, IAzaxView
from pluginregistry.commandset import getRegisteredCommandSet
from zope import app, component, interface
-from zope.app.component.hooks import setSite, setHooks
-from zope.app.component.interfaces import ISite, ILocalSiteManager
-from zope.app.component.site import clearSite
+from zope.component import getSiteManager
from zope.component.globalregistry import BaseGlobalComponents
+from zope.component.persistentregistry import PersistentAdapterRegistry
from zope.component.interfaces import IComponentLookup
+from zope.component.interfaces import ComponentLookupError
from zope.event import notify
from zope.interface import implements, Interface
from zope.publisher.browser import BrowserView
-from zope.component.persistentregistry import PersistentAdapterRegistry
-from zope.app.component.site import _findNextSiteManager
-from zope.component.interfaces import ComponentLookupError
class ViewSiteManager(BaseGlobalComponents):
@@ -62,7 +59,6 @@
class SiteView(BrowserView):
"""A browser view that is its own site
"""
- implements(ISite)
def __init__(self, context, request):
super(SiteView, self).__init__(context, request)
@@ -85,14 +81,12 @@
# register object event handler
self._sitemanager.registerHandler(wrapped_view._eventRedispatcher)
- ##setHooks()
- ##setSite(self)
- def getSiteManager(self):
- return self._sitemanager
+ # make ourselve the default site manager
+ getSiteManager.sethook(self.getSiteManager)
- def setSiteManager(self, sm):
- raise NotImplementedError('You can only get the site manager')
+ def getSiteManager(self, context=None):
+ return self._sitemanager
@component.adapter(Interface)
def _eventRedispatcher(self, event):
@@ -101,7 +95,8 @@
notify(azaxevent)
def render(self):
- pass #clearSite()
+ # reset the site manager to its original one
+ getSiteManager.reset()
class AzaxBaseView(SiteView):
""" Base kss view
Modified: kukit/kss.core/trunk/azaxview.txt
==============================================================================
--- kukit/kss.core/trunk/azaxview.txt (original)
+++ kukit/kss.core/trunk/azaxview.txt Sat Dec 16 00:01:34 2006
@@ -25,6 +25,7 @@
>>> from zope.app.component.interfaces import ISite
>>> from zope.interface import directlyProvides, directlyProvidedBy
>>> from zope.publisher.browser import TestRequest
+ >>> import zope.component.event
>>> from zope.app.folder import folder
>>> myfolder = folder.rootFolder()
Modified: kukit/kss.core/trunk/tests/test_azaxview.py
==============================================================================
--- kukit/kss.core/trunk/tests/test_azaxview.py (original)
+++ kukit/kss.core/trunk/tests/test_azaxview.py Sat Dec 16 00:01:34 2006
@@ -39,6 +39,7 @@
from zope import component
from Products.Five import zcml
import Products.Five
+import zope.component.event
#from zope.app.component.hooks import setSite, getSite, setHooks
def setUpDoctTest(test=None):
From jvloothuis at codespeak.net Sat Dec 16 11:51:27 2006
From: jvloothuis at codespeak.net (jvloothuis at codespeak.net)
Date: Sat, 16 Dec 2006 11:51:27 +0100 (CET)
Subject: [KSS-checkins] r35831 - kukit/kss.core/trunk
Message-ID: <20061216105127.7F4BC1007F@code0.codespeak.net>
Author: jvloothuis
Date: Sat Dec 16 11:51:24 2006
New Revision: 35831
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/azaxview.txt
kukit/kss.core/trunk/siteview.txt
Log:
Added a stopEventListening method to the site view. This makes it possible to deregister the view for event interception. The change will be used in unit tests but also may have some merrit in specific places.
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 11:51:24 2006
@@ -94,9 +94,13 @@
azaxevent = AzaxEvent(self, event)
notify(azaxevent)
- def render(self):
+ def stopEventListening(self):
# reset the site manager to its original one
- getSiteManager.reset()
+ if self.getSiteManager() is component.getSiteManager():
+ getSiteManager.reset()
+
+ def render(self):
+ self.stopEventListening()
class AzaxBaseView(SiteView):
""" Base kss view
Modified: kukit/kss.core/trunk/azaxview.txt
==============================================================================
--- kukit/kss.core/trunk/azaxview.txt (original)
+++ kukit/kss.core/trunk/azaxview.txt Sat Dec 16 11:51:24 2006
@@ -25,7 +25,6 @@
>>> from zope.app.component.interfaces import ISite
>>> from zope.interface import directlyProvides, directlyProvidedBy
>>> from zope.publisher.browser import TestRequest
- >>> import zope.component.event
>>> from zope.app.folder import folder
>>> myfolder = folder.rootFolder()
Modified: kukit/kss.core/trunk/siteview.txt
==============================================================================
--- kukit/kss.core/trunk/siteview.txt (original)
+++ kukit/kss.core/trunk/siteview.txt Sat Dec 16 11:51:24 2006
@@ -2,9 +2,9 @@
Site view
=========
-All Azax views are not only a browser view but a site as well. A site is Zope
-used as a local component registry. You can hookup adapters etc. in such a
-place. Azax views are made sites to intercept all incomming events.
+All Azax views are not only a browser view but provide a site manager as well.
+The site manager is hooked into the component framework on creation time. This
+allows the Azax views to intercept all incomming events.
By doing so the view is able to hookup it's own event redispatcher. This is a
normal event handler which generates the specific Azax events. These events
@@ -15,7 +15,7 @@
instance when you change a title in a document you also want the menu reloaded.
By using events for this we can achieve a degree of decoupling.
-The main class which implements views as a site is `SiteView`.
+The main class which implements views with a site manager is `SiteView`.
>>> from kss.core.azaxview import SiteView
@@ -69,3 +69,23 @@
>>> view.render()
>>> view.getSiteManager() is component.getSiteManager()
False
+
+The view also has a specific way of unregistering itself for events. You can
+use this from your tests or other specific use cases. First we will create a
+new view to start listening.
+
+ >>> view = SiteView(None, None)
+
+Now we will stop the view from listening to the events.
+
+ >>> view.stopEventListening()
+
+If we raise an event we should only get the one event and not the AzaxEvent as well.
+
+ >>> clearEvents()
+ >>> notify(ObjectModifiedEvent(None))
+ >>> len(getEvents())
+ 1
+ >>> original_event = getEvents()[0]
+ >>> IObjectModifiedEvent.providedBy(original_event)
+ True
From jvloothuis at codespeak.net Sat Dec 16 12:11:13 2006
From: jvloothuis at codespeak.net (jvloothuis at codespeak.net)
Date: Sat, 16 Dec 2006 12:11:13 +0100 (CET)
Subject: [KSS-checkins] r35832 - kukit/kss.core/trunk
Message-ID: <20061216111113.4E82F1007F@code0.codespeak.net>
Author: jvloothuis
Date: Sat Dec 16 12:11:08 2006
New Revision: 35832
Modified:
kukit/kss.core/trunk/azaxview.py
Log:
Made the stop event listening method set the hook to the previous one instead of resitting it. This should make sure that it doesn't break other overrides.
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Sat Dec 16 12:11:08 2006
@@ -63,11 +63,11 @@
def __init__(self, context, request):
super(SiteView, self).__init__(context, request)
- next_sitemanager = component.getSiteManager()
+ _next_sitemanager = component.getSiteManager()
self._sitemanager = ViewSiteManager('siteview')
- self._sitemanager.__bases__ = (next_sitemanager, )
+ self._sitemanager.__bases__ = (_next_sitemanager, )
# On Five, we should wrap it in the acquisition context
# see, if self has aq_parent, it is done obligatoraly
@@ -82,7 +82,10 @@
# register object event handler
self._sitemanager.registerHandler(wrapped_view._eventRedispatcher)
- # make ourselve the default site manager
+
+ # first get a reference to the old implementation before making
+ # ourselves the new default site manager
+ self._getSiteManagerHook = getSiteManager.implementation
getSiteManager.sethook(self.getSiteManager)
def getSiteManager(self, context=None):
@@ -96,8 +99,7 @@
def stopEventListening(self):
# reset the site manager to its original one
- if self.getSiteManager() is component.getSiteManager():
- getSiteManager.reset()
+ getSiteManager.sethook(self._getSiteManagerHook)
def render(self):
self.stopEventListening()
From jvloothuis at codespeak.net Tue Dec 19 21:16:47 2006
From: jvloothuis at codespeak.net (jvloothuis at codespeak.net)
Date: Tue, 19 Dec 2006 21:16:47 +0100 (CET)
Subject: [KSS-checkins] r35903 - kukit/kss.core/trunk
Message-ID: <20061219201647.B542110075@code0.codespeak.net>
Author: jvloothuis
Date: Tue Dec 19 21:16:45 2006
New Revision: 35903
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/azaxview.txt
Log:
Removed unneeded handle method which did the same as event.notify
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Tue Dec 19 21:16:45 2006
@@ -140,12 +140,6 @@
def getCommands(self):
return self.commands
- def handle(self, *args):
- for event in args: # first fire all normal stuff
- notify(event)
- for event in args: # now do the kss bits
- component.handle(AzaxEvent(self, event))
-
def getCommandSet(self, name):
commandset = getRegisteredCommandSet(name)
# return the adapted view
Modified: kukit/kss.core/trunk/azaxview.txt
==============================================================================
--- kukit/kss.core/trunk/azaxview.txt (original)
+++ kukit/kss.core/trunk/azaxview.txt Tue Dec 19 21:16:45 2006
@@ -25,6 +25,7 @@
>>> from zope.app.component.interfaces import ISite
>>> from zope.interface import directlyProvides, directlyProvidedBy
>>> from zope.publisher.browser import TestRequest
+ >>> from zope import event
>>> from zope.app.folder import folder
>>> myfolder = folder.rootFolder()
@@ -39,7 +40,7 @@
>>> class SampleView(AzaxBaseView):
... def add_page(self, title):
... # normally you would change the zope database here
- ... self.handle(ObjectModifiedEvent(title))
+ ... event.notify(ObjectModifiedEvent(title))
... return self.render()
>>> view = SampleView(myfolder, request)
@@ -59,26 +60,6 @@
When we call the renderer now it should have some more data in it.
+ >>> view = SampleView(myfolder, request)
>>> view.add_page("some title")[0]['params']['html']
u'some title'
-
-The example above used our convenience method to generate events. You normally
-do this for all mutations you make yourself. Not all events are generated this
-way though. In case of a workflow transition events may be fired as well. Azax
-views account for this automatically. You don't need to do anything special.
-
-We will demonstrate this using a simple view. This view will generate the
-modified event through normal component api instead of our handle method.
-
- >>> class AnotherView(AzaxBaseView):
- ... def add_page(self, title):
- ... # normally you would change the zope database here
- ... notify(ObjectModifiedEvent(title))
- ... return self.render()
-
-This should now still invoke our handler.
-
- >>> view = AnotherView(myfolder, request)
- >>> view.add_page("another title")[0]['params']['html']
- u'another title'
-
From reebalazs at codespeak.net Fri Dec 22 11:31:35 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Fri, 22 Dec 2006 11:31:35 +0100 (CET)
Subject: [KSS-checkins] r35946 - in kukit/kss.core/trunk: . tests
Message-ID: <20061222103135.1A12C10082@code0.codespeak.net>
Author: reebalazs
Date: Fri Dec 22 11:31:16 2006
New Revision: 35946
Added:
kukit/kss.core/trunk/siteview_life.txt
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/tests/base.py
kukit/kss.core/trunk/tests/test_siteview.py
Log:
kss: fix the siteview. It needs to stopEventListening if an EndRequest event arrives. Without this the failing requests linger forever listening, and only zope restart clears the situation.
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Fri Dec 22 11:31:16 2006
@@ -49,6 +49,7 @@
from zope.event import notify
from zope.interface import implements, Interface
from zope.publisher.browser import BrowserView
+from zope.app.publication.interfaces import IEndRequestEvent
class ViewSiteManager(BaseGlobalComponents):
@@ -93,6 +94,10 @@
@component.adapter(Interface)
def _eventRedispatcher(self, event):
+ if IEndRequestEvent.providedBy(event):
+ # If this happens, we must finish activity
+ self.stopEventListening()
+ return
if not IAzaxEvent.providedBy(event):
azaxevent = AzaxEvent(self, event)
notify(azaxevent)
Added: kukit/kss.core/trunk/siteview_life.txt
==============================================================================
--- (empty file)
+++ kukit/kss.core/trunk/siteview_life.txt Fri Dec 22 11:31:16 2006
@@ -0,0 +1,104 @@
+=====================
+Site view, life cycle
+=====================
+
+... or, making the view a site manager is a good idea after
+all, but let's see what dangers are lurking in the dark.
+
+Checking if the view finishes its lifetime
+------------------------------------------
+
+It is important that the view does not stay on after the
+request. This would cause them to continue listening to
+events. We need a few imports first.
+
+ >>> from kss.core.azaxview import SiteView
+
+ >>> from zope.interface import Interface, implements
+ >>> from zope.component import adapter
+ >>> from zope.lifecycleevent import ObjectModifiedEvent
+ >>> from zope.event import notify
+ >>> from zope.app.publication.interfaces import IEndRequestEvent
+ >>> try:
+ ... from Products.Five.testbrowser import Browser
+ ... except ImportError:
+ ... from zope.testbrowser.browser import Browser
+
+First, let's create a funky view that has two methods, one
+failing and one succeeding, and a habit to choke on any
+events.
+
+ >>> class FunkyView(SiteView):
+ ... def IAmGood(self):
+ ... 'XXX'
+ ... return self.render()
+ ... def IAmBad(self):
+ ... 'XXX'
+ ... raise Exception, 'Generic badness'
+ ... @adapter(Interface)
+ ... def _eventRedispatcher(self, event):
+ ... SiteView._eventRedispatcher(self, event)
+ ... if not IEndRequestEvent.providedBy(event):
+ ... raise Exception, 'Too late event %r' % event
+
+ >>> import kss.core.tests
+ >>> kss.core.tests.FunkyView = FunkyView
+
+We provide this view as a browser page. We care to register
+it properly, otherwise we would miss some Five acquisition
+woodoo. (XXX Note that this must be adjusted to run on Zope3.)
+
+ >>> try:
+ ... import Products.Five
+ ... except ImportError:
+ ... # probably zope 3, not supported
+ ... raise 'Zope3 not supported in this test'
+ ... else:
+ ... from Products.Five.zcml import load_string, load_config
+
+ >>> load_string('''
+ ...
+ ...
+ ...
+ ...
+ ... ''')
+
+Create a test browser now, so we can finally start.
+
+ >>> browser = Browser()
+
+Let's call up the good request.
+
+ >>> browser.open(self.folder.absolute_url() + '/@@funky_view/IAmGood')
+
+Now, if we happen to send an event... nothing happens, since
+the render() method has taken care of unregistering the
+event as a SiteView.
+
+ >>> notify(ObjectModifiedEvent(None))
+
+But it is also important, that even in case the render
+method does not run (it gives an error since we raised an
+exception, this is all right). We would already get an error
+during this, thanks to the RequestEvent that arrives.
+
+ >>> browser = browser.open('http://nohost/@@funky_view/IAmBad')
+ Traceback (most recent call last):
+ ...
+ HTTPError: HTTP Error 500: Internal Server Error
+
+And even if we send a new event, it must not get to the
+redispatcher of the view.
+
+ >>> notify(ObjectModifiedEvent(None))
+
Modified: kukit/kss.core/trunk/tests/base.py
==============================================================================
--- kukit/kss.core/trunk/tests/base.py (original)
+++ kukit/kss.core/trunk/tests/base.py Fri Dec 22 11:31:16 2006
@@ -19,7 +19,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
-from Testing.ZopeTestCase import ZopeTestCase
+from Testing.ZopeTestCase import ZopeTestCase, FunctionalTestCase
import kss.core
from kss.core import AzaxBaseView
from OFS.SimpleItem import SimpleItem
@@ -49,7 +49,7 @@
class IDebugRequest(IBrowserRequest):
'The debug request'
-class AzaxViewTestCase(ZopeTestCase):
+class KssViewTestCase(ZopeTestCase):
def afterSetUp(self):
placelesssetup.setUp()
@@ -120,3 +120,10 @@
else:
import Products.Five.zcml
Products.Five.zcml._context = None
+
+class KssViewFunctionalTestCase(FunctionalTestCase, KssViewTestCase):
+ 'Functional test base'
+
+
+# backward compatibility
+AzaxViewTestCase = KssViewTestCase
Modified: kukit/kss.core/trunk/tests/test_siteview.py
==============================================================================
--- kukit/kss.core/trunk/tests/test_siteview.py (original)
+++ kukit/kss.core/trunk/tests/test_siteview.py Fri Dec 22 11:31:16 2006
@@ -1,25 +1,14 @@
-#from base import AzaxViewTestCase, FakeContent, TestRequest, DebugTestRequest
-#from kss.core import AzaxUnicodeError
-#from kss.core.events import AzaxEvent
-#from kss.core.interfaces import IAzaxCommands, IAzaxEvent
-#from kss.core.interfaces import IAzaxView
-#from kss.core.pluginregistry.action import Action
-#from kss.core.pluginregistry.commandset import CommandSet
-#from kss.core.pluginregistry.interfaces import IAction, ICommandSet
-#from kss.core.pluginregistry.plugin import registerPlugin
-#from kss.core.plugins.core.commands import KSSCoreCommands
-#from kss.core.plugins.core.interfaces import IKSSCoreCommands
-#from kss.core.tests.base import IDebugRequest
-#from kss.core.tests.commandinspector import CommandInspectorView
from Products.Five import zcml
from zope import component
from zope.component import eventtesting
from zope.testing import doctest
from zope.testing.cleanup import CleanUp as PlacelessSetup
import Products.Five
-import unittest #, os
+import unittest
+from Testing.ZopeTestCase import FunctionalDocFileSuite
+from base import KssViewFunctionalTestCase
-def setUpDoctTest(test=None):
+def setUpDocTest(test=None):
PlacelessSetup().setUp()
eventtesting.setUp()
@@ -29,11 +18,31 @@
zcml.load_config("configure.zcml", Products.Five.site)
-def tearDownDoctTest(test=None):
+def tearDownDocTest(test=None):
PlacelessSetup().tearDown()
+def setUpFDocTest(test=None):
+ #PlacelessSetup().setUp()
+ KssViewFunctionalTestCase.setUp(test)
+ eventtesting.setUp()
+
+# zcml.load_config("meta.zcml", Products.Five)
+# zcml.load_config("permissions.zcml", Products.Five)
+# zcml.load_config("configure.zcml", Products.Five.component)
+#
+# zcml.load_config("configure.zcml", Products.Five.site)
+# zcml.load_config("configure.zcml", Products.Five.site)
+
+def tearDownFDocTest(test=None):
+ #PlacelessSetup().tearDown()
+ KssViewFunctionalTestCase.tearDown(test)
+
def test_suite():
- suite = doctest.DocFileSuite('../siteview.txt',
- setUp=setUpDoctTest,
- tearDown=tearDownDoctTest)
+ suite = FunctionalDocFileSuite('../siteview.txt',
+ setUp=setUpDocTest,
+ tearDown=tearDownDocTest)
+ suite = FunctionalDocFileSuite('../siteview_life.txt',
+ test_class=KssViewFunctionalTestCase,
+ setUp=setUpFDocTest,
+ tearDown=tearDownFDocTest)
return unittest.TestSuite(suite)
From reebalazs at codespeak.net Fri Dec 22 12:01:18 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Fri, 22 Dec 2006 12:01:18 +0100 (CET)
Subject: [KSS-checkins] r35948 - in kukit/kss.core/trunk: . plugins/core
plugins/effects
Message-ID: <20061222110118.DABB910086@code0.codespeak.net>
Author: reebalazs
Date: Fri Dec 22 12:01:15 2006
New Revision: 35948
Modified:
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/interfaces.py
kukit/kss.core/trunk/plugins/core/commands.py
kukit/kss.core/trunk/plugins/effects/commands.py
Log:
Renamed AzaxViewAdapter to CommandSet. Fixed its lieing interface. Moved __allow...unprotected to the CommandSet from the plugin implementations.
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Fri Dec 22 12:01:15 2006
@@ -38,7 +38,7 @@
from commands import AzaxCommands
from events import AzaxEvent
-from interfaces import IAzaxEvent, IAzaxView
+from interfaces import IAzaxEvent, IAzaxView, ICommandSet
from pluginregistry.commandset import getRegisteredCommandSet
from zope import app, component, interface
from zope.component import getSiteManager
@@ -150,8 +150,13 @@
# return the adapted view
return commandset.provides(self)
-class AzaxViewAdapter:
- implements(IAzaxView)
+class CommandSet:
+ implements(ICommandSet)
+
+ # XXX This is really bad. Is is needed for restricted access?
+ # If not, it has to go. If no, it needs an alternate solution.
+ # also we need test for this.
+ __allow_access_to_unprotected_subobjects__ = True
def __init__(self, view):
self.view = view
@@ -161,3 +166,6 @@
def getCommandSet(self, name):
return self.view.getCommandSet(name)
+
+# XXX to be deprecated
+AzaxViewAdapter = CommandSet
Modified: kukit/kss.core/trunk/interfaces.py
==============================================================================
--- kukit/kss.core/trunk/interfaces.py (original)
+++ kukit/kss.core/trunk/interfaces.py Fri Dec 22 12:01:15 2006
@@ -110,6 +110,12 @@
def render():
''
+class ICommandSet(Interface):
+ 'Methods of this class implement a command set'
+
+ def getCommandSet(self, name):
+ 'Returns the command set for a given name'
+
class IAzaxEvent(Interface):
"""Used to notify of events during an Ajax call
Modified: kukit/kss.core/trunk/plugins/core/commands.py
==============================================================================
--- kukit/kss.core/trunk/plugins/core/commands.py (original)
+++ kukit/kss.core/trunk/plugins/core/commands.py Fri Dec 22 12:01:15 2006
@@ -1,13 +1,12 @@
from interfaces import IKSSCoreCommands
from kss.core.selectors import Selector, CssSelector, HtmlIdSelector
-from kss.core.azaxview import AzaxViewAdapter
+from kss.core.azaxview import CommandSet
from kss.core.deprecated import deprecated
from kss.core.parsers import XmlParser, HtmlParser
from kss.core.plugins.core.interfaces import IKSSCoreCommands
from zope.interface import implements
-class KSSCoreCommands(AzaxViewAdapter):
- __allow_access_to_unprotected_subobjects__ = 1
+class KSSCoreCommands(CommandSet):
implements(IKSSCoreCommands)
def getSelector(self, type, selector):
Modified: kukit/kss.core/trunk/plugins/effects/commands.py
==============================================================================
--- kukit/kss.core/trunk/plugins/effects/commands.py (original)
+++ kukit/kss.core/trunk/plugins/effects/commands.py Fri Dec 22 12:01:15 2006
@@ -1,8 +1,7 @@
from interfaces import IScriptaculousEffectsCommands
-from kss.core.azaxview import AzaxViewAdapter
+from kss.core.azaxview import CommandSet
-class ScriptaculousEffectsCommands(AzaxViewAdapter):
- __allow_access_to_unprotected_subobjects__ = 1
+class ScriptaculousEffectsCommands(CommandSet):
def effect(self, selector, type):
""" see interfaces.py """
From reebalazs at codespeak.net Tue Dec 26 12:16:46 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 26 Dec 2006 12:16:46 +0100 (CET)
Subject: [KSS-checkins] r35983 - kukit/kukit.js/trunk/kukit
Message-ID: <20061226111646.969381007A@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 26 12:16:44 2006
New Revision: 35983
Modified:
kukit/kukit.js/trunk/kukit/kukit.js
kukit/kukit.js/trunk/kukit/plugin.js
Log:
Implement an error command that can be used to signal an error condition with a reason displayed in the kss log.
Modified: kukit/kukit.js/trunk/kukit/kukit.js
==============================================================================
--- kukit/kukit.js/trunk/kukit/kukit.js (original)
+++ kukit/kukit.js/trunk/kukit/kukit.js Tue Dec 26 12:16:44 2006
@@ -221,6 +221,16 @@
/* Server notification */
+// this should be thrown with the error command as parameter
+kukit.ExplicitError = kukit.ut.exceptionFactory('ExplicitError');
+kukit.ExplicitError.prototype.__superinit__ = kukit.ExplicitError.prototype.__init__;
+kukit.ExplicitError.prototype.__init__ = function(name, errorcommand) {
+ var message = 'Explicit error, reason=' + errorcommand.parms.message;
+ var kw = this.__superinit__(name, message);
+ kw.errorcommand = errorcommand;
+ return kw
+};
+
// Backparms can be used on command execution.
kukit.notifyServer = function(url, params, oper) {
var sendHook = function(queueItem) {
@@ -278,6 +288,8 @@
kukit.logFatal(msg);
// just throw it too...
throw msg;
+ } else if (e.name == 'ExplicitError') {
+ kukit.processError(oper, e.errorcommand);
} else {
kukit.logError('Unhandled error during command execution: ' + e);
// also IE acts foul on thrown errors
@@ -312,8 +324,7 @@
// 1. No response from server, and browser notifies us with an empty response
// 2. There was an error on the server, and we got an error message as response
// Call the error handler.
- kukit.processError(oper);
- return;
+ throw new kukit.ExplicitError();
}
// Opera <= 8.5 does not have the parseError attribute, so check for it first
if (domXml.parseError && (domXml.parseError != 0)) {
@@ -330,18 +341,22 @@
command_processor.executeCommands(oper);
};
-kukit.processError = function(oper) {
+kukit.processError = function(oper, errorcommand) {
var error_action = null;
if (oper.eventrule) {
var error_action = oper.eventrule.actions.getErrorActionFor(oper.action);
}
+ var reason = '';
+ if (typeof(errorcommand) != 'undefined') {
+ reason = ', reason="' + errorcommand.parms.message + '" '
+ }
if (error_action) {
- kukit.logWarning('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + ', will be handled by action "' + error_action.name + '"');
+ kukit.logWarning('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid + reason + ', will be handled by action "' + error_action.name + '"');
// Individual error handler was defined. Execute it!
error_action.execute(oper);
} else {
// Unhandled: just log it...
- kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid);
+ kukit.logError('Request failed at url ' + oper.queueItem.url + ', rid=' + oper.queueItem.rid) + reason;
}
};
@@ -363,6 +378,14 @@
for (var y=0;y < commands.length;y++) {
var command = commands[y];
this.parseCommand(command, transport);
+ // If we receive an error command, we handle that separately.
+ // We abort immediately and let the processError handler do its job.
+ // This means that although no other commands should be in commands,
+ // we make sure we execute none of them.
+ var lastcommand = this.commands[this.commands.length-1];
+ if (lastcommand.name == 'error') {
+ throw new kukit.ExplicitError(lastcommand);
+ }
}
};
Modified: kukit/kukit.js/trunk/kukit/plugin.js
==============================================================================
--- kukit/kukit.js/trunk/kukit/plugin.js (original)
+++ kukit/kukit.js/trunk/kukit/plugin.js Tue Dec 26 12:16:44 2006
@@ -312,6 +312,12 @@
* They also get registered as commands
*/
+kukit.ar.actionRegistry.register("error", function (oper) {
+ throw 'The builtin error action should never execute.';
+ }
+);
+kukit.cr.commandRegistry.registerFromAction('error', kukit.cr.makeGlobalCommand);
+
kukit.ar.actionRegistry.register("logDebug", function (oper) {
oper.completeParms([], {'message': 'Logging from Event'}, 'logDebug action');
var node = oper.node;
From reebalazs at codespeak.net Tue Dec 26 12:24:56 2006
From: reebalazs at codespeak.net (reebalazs at codespeak.net)
Date: Tue, 26 Dec 2006 12:24:56 +0100 (CET)
Subject: [KSS-checkins] r35984 - in kukit/kss.core/trunk: . plugins/core
tests
Message-ID: <20061226112456.F08F61007A@code0.codespeak.net>
Author: reebalazs
Date: Tue Dec 26 12:24:54 2006
New Revision: 35984
Added:
kukit/kss.core/trunk/actionwrapper.py
Modified:
kukit/kss.core/trunk/__init__.py
kukit/kss.core/trunk/azaxview.py
kukit/kss.core/trunk/plugins/core/configure.zcml
kukit/kss.core/trunk/tests/test_azaxview.py
Log:
Implement kssaction wrapper for action view methods
This is an alternate way of making view methods. First, self.render()
is not needed to be returned at the end. Second, if KssExplicitError
is raised, that will not cause an error log on the server, but
instead it sends the error command to the client, which in return
displays the fallback reason and executes its error action.
Modified: kukit/kss.core/trunk/__init__.py
==============================================================================
--- kukit/kss.core/trunk/__init__.py (original)
+++ kukit/kss.core/trunk/__init__.py Tue Dec 26 12:24:54 2006
@@ -18,16 +18,18 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
#
-__all__ = ('AzaxBaseView', 'force_unicode', 'AzaxUnicodeError', 'AzaxCommands')
+__all__ = ('AzaxBaseView', 'force_unicode', 'AzaxUnicodeError',
+ 'IKssExplicitError', 'KssExplicitError', 'kssaction',
+ )
import mimetypes
mimetypes.types_map['.kkt'] = 'text/xml' # XXX legacy!
mimetypes.types_map['.kukit'] = 'text/xml'
-from azaxview import AzaxBaseView
+from azaxview import AzaxBaseView
+from actionwrapper import KssExplicitError, kssaction
from unicode_quirks import force_unicode, AzaxUnicodeError
-from commands import AzaxCommands, AzaxCommand, AzaxParam
try:
import Products.Five
@@ -36,6 +38,7 @@
else:
# Allow to build commands from restricted code
from AccessControl import allow_class
+ from commands import AzaxCommands, AzaxCommand, AzaxParam
allow_class(AzaxCommands)
allow_class(AzaxCommand)
allow_class(AzaxParam)
Added: kukit/kss.core/trunk/actionwrapper.py
==============================================================================
--- (empty file)
+++ kukit/kss.core/trunk/actionwrapper.py Tue Dec 26 12:24:54 2006
@@ -0,0 +1,248 @@
+# Copyright (c) 2005-2006
+# Authors: KSS project contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as published
+# by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+
+from textwrap import dedent
+from inspect import formatargspec, getargspec, getargvalues, \
+ formatargvalues, currentframe
+from zope.interface import implements
+
+class KssExplicitError(Exception):
+ 'Explicit error to be raised'
+
+class kssaction(object):
+ '''Descriptor to bundle kss server actions.
+
+ - render() will be called automatically if there is no
+ return value
+
+ - if KssExplicitError is raised, a normal response is returned,
+ containing a single command:error azax command.
+
+ Let's say we have a class here - that is supposed to be a kss view.
+
+ >>> from kss.core import kssaction, KssExplicitError, AzaxBaseView
+
+ >>> class MyView(AzaxBaseView):
+ ... def ok(self, a, b, c=0):
+ ... return 'OK %s %s %s' % (a, b, c)
+ ... def notok(self, a, b, c=0):
+ ... pass
+ ... def error(self, a, b, c=0):
+ ... raise KssExplicitError, 'The error'
+ ... def exception(self, a, b, c=0):
+ ... raise Exception, 'Unknown exception'
+
+ Now we try qualifying with kssaction. We overwrite render too,
+ just to enable sensible testing of the output:
+
+ >>> class MyView(AzaxBaseView):
+ ... def render(self):
+ ... return 'Rendered'
+ ... @kssaction
+ ... def ok(self, a, b, c=3):
+ ... return 'OK %s %s %s' % (a, b, c)
+ ... @kssaction
+ ... def notok(self, a, b, c=3):
+ ... pass
+ ... @kssaction
+ ... def error(self, a, b, c=3):
+ ... raise KssExplicitError, 'The error'
+ ... @kssaction
+ ... def exception(self, a, b, c=3):
+ ... raise Exception, 'Unknown exception'
+
+ Instantiate a view.
+
+ >>> view = MyView(None, None)
+
+ Now, of course ok renders well.
+
+ >>> view.ok(1, b=2)
+ 'OK 1 2 3'
+
+ Not ok will have implicit rendering.
+
+ >>> view.notok(1, b=2)
+ 'Rendered'
+
+ The third type will return an error action. But it will render
+ instead of an error.
+
+ >>> view.error(1, b=2)
+ 'Rendered'
+
+ The fourth type will be a real error.
+
+ >>> view.exception(1, b=2)
+ Traceback (most recent call last):
+ ...
+ Exception: Unknown exception
+
+ Now for the sake of it, let's test the rendered kukit response.
+ So, we don't overwrite render like as we did in the previous
+ tests.
+
+ >>> from zope.publisher.browser import TestRequest
+
+ >>> class MyView(AzaxBaseView):
+ ... @kssaction
+ ... def error(self, a, b, c=3):
+ ... raise KssExplicitError, 'The error'
+ ... @kssaction
+ ... def with_docstring(self, a, b, c=3):
+ ... "Docstring"
+ ... raise KssExplicitError, 'The error'
+
+ >>> request = TestRequest()
+ >>> view = MyView(None, request)
+
+ Set debug-mode command rendering so we can see the results in a
+ more structured form.
+
+ >>> from zope import interface as iapi
+ >>> from kss.core.tests.base import IDebugRequest
+ >>> iapi.directlyProvides(request, iapi.directlyProvidedBy(request) + IDebugRequest)
+
+ See the results:
+
+ >>> view.error(1, b=2)
+ [{'selectorType': None, 'params': {'message': u'The error'}, 'name': 'error', 'selector': None}]
+
+ Usage of the method wrapped in browser view
+ -------------------------------------------
+
+ Finally, let's check if the method appears if defined on a browser view.
+ Since there could be a thousand reasons why Five's magic could fail,
+ it's good to check this. (XXX Note that this must be adjusted to run on Zope3.)
+
+ >>> try:
+ ... import Products.Five
+ ... except ImportError:
+ ... # probably zope 3, not supported
+ ... raise 'Zope3 not supported in this test'
+ ... else:
+ ... from Products.Five.zcml import load_string, load_config
+
+ >>> import kss.core.tests
+ >>> kss.core.tests.MyView = MyView
+
+ We check for two basic types of declaration. The first one declares
+ a view with different attributes. The second one declares a dedicated
+ view with the method as the view default method. This is how we use
+ it in several places.
+
+ >>> load_string("""
+ ...
+ ...
+ ...
+ ...
+ ...
+ ...
+ ... """)
+
+ Let's check it now:
+
+ >>> self.folder.restrictedTraverse('/@@my_view/error')
+ >> v = self.folder.restrictedTraverse('/my_view2')
+ >>> isinstance(v, MyView)
+ True
+ >>> hasattr(v, 'error')
+ True
+ >>> v(1, b=2)
+ [{'selectorType': None, 'params': {'message': u'The error'}, 'name': 'error', 'selector': None}]
+
+ In addition, to be publishable, the docstring must exist. Let's
+ see if the wrapper actually does this. If the method had a docstring,
+ it will be reused, but a docstring is provided in any case.
+
+ >>> v = self.folder.restrictedTraverse('/@@my_view')
+ >>> bool(v.error.__doc__)
+ True
+
+ >>> v.with_docstring.__doc__
+ 'Docstring'
+
+ '''
+ def __init__(self, f):
+ self.f = f
+ # Now this is a solution I don't like, but we need the same
+ # function signature, otherwise the ZPublisher won't marshall
+ # the parameters. *arg, **kw would not suffice since no parameters
+ # would be marshalled at all.
+ argspec = getargspec(f)
+ orig_args = formatargspec(*argspec)[1:-1]
+ if argspec[3] is None:
+ fixed_args_num = len(argspec[0])
+ else:
+ fixed_args_num = len(argspec[0]) - len(argspec[3])
+ values_list = [v for v in argspec[0][:fixed_args_num]]
+ values_list.extend(['%s=%s' % (v, v) for v in argspec[0][fixed_args_num:]])
+ values_args = ', '.join(values_list)
+ # provide a docstring in any case.
+ if self.f.__doc__ is not None:
+ docstring = repr(f.__doc__)
+ else:
+ docstring = '"XXX"'
+ # orig_args: "a, b, c=2"
+ # values_args: "a, b, c=c"
+ code = dedent('''\n
+ def wrapper(%s):
+ %s
+ return descr.apply(%s)
+ ''' % (orig_args, docstring, values_args))
+ self.wrapper_code = compile(code, '', 'exec')
+
+ def __get__(self, obj, cls=None):
+ d = {'descr': self, 'self': obj}
+ exec(self.wrapper_code, d)
+ wrapper = d['wrapper'].__get__(obj, cls)
+ return wrapper
+
+ def apply(self, obj, *arg, **kw):
+ try:
+ result = self.f(obj, *arg, **kw)
+ except KssExplicitError, exc:
+ # Clear all the commands, and emit an error command
+ obj._initcommands()
+ obj.commands.addCommand('error', message=str(exc))
+ result = None
+ if result is None:
+ # render not returned - so we do it.
+ result = obj.render()
+ return result
Modified: kukit/kss.core/trunk/azaxview.py
==============================================================================
--- kukit/kss.core/trunk/azaxview.py (original)
+++ kukit/kss.core/trunk/azaxview.py Tue Dec 26 12:24:54 2006
@@ -120,6 +120,9 @@
def __init__(self, context, request):
super(AzaxBaseView, self).__init__(context, request)
+ self._initcommands()
+
+ def _initcommands(self):
self.commands = AzaxCommands()
def _set_context(self, context):
Modified: kukit/kss.core/trunk/plugins/core/configure.zcml
==============================================================================
--- kukit/kss.core/trunk/plugins/core/configure.zcml (original)
+++ kukit/kss.core/trunk/plugins/core/configure.zcml Tue Dec 26 12:24:54 2006
@@ -112,7 +112,15 @@
-
+
+
+
+
+
Author: reebalazs
Date: Tue Dec 26 12:25:39 2006
New Revision: 35985
Modified:
kukit/kss.demo/trunk/azaxview.py
kukit/kss.demo/trunk/browser/error_handling.pt
Log:
Modify the error_handling demo to check the explitit error marshalling.
Modified: kukit/kss.demo/trunk/azaxview.py
==============================================================================
--- kukit/kss.demo/trunk/azaxview.py (original)
+++ kukit/kss.demo/trunk/azaxview.py Tue Dec 26 12:25:39 2006
@@ -19,7 +19,7 @@
# 02111-1307, USA.
#
-from kss.core import AzaxBaseView, force_unicode
+from kss.core import AzaxBaseView, force_unicode, KssExplicitError, kssaction
import datetime
class AzaxView(AzaxBaseView):
@@ -154,9 +154,12 @@
self.getCommandSet('effects').effect('.effects', 'appear')
return self.render()
+ @kssaction
def errTest(self, id, act):
if act == 'error':
raise Exception, 'We have an error here.'
+ elif act == 'explicit':
+ raise KssExplicitError, 'Explicit error raised.'
elif act == 'empty':
# Just do nothing, we want to return a response with no commands.
# This is valid behaviour, should raise no error, however
Modified: kukit/kss.demo/trunk/browser/error_handling.pt
==============================================================================
--- kukit/kss.demo/trunk/browser/error_handling.pt (original)
+++ kukit/kss.demo/trunk/browser/error_handling.pt Tue Dec 26 12:25:39 2006
@@ -42,6 +42,8 @@
value="Error" />
+
The buttons in the second row have individual error handlers.