summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-01-15 00:20:04 +0000
committerChris McDonough <chrism@agendaless.com>2009-01-15 00:20:04 +0000
commitc8cf2256655ee4b34ec501325b9016608b5cce5f (patch)
tree065c104d852d70389ce328813e2e8ea33e9885ce
parentec54985a5c27846a7e9444c22bcf46ae7e868b66 (diff)
downloadpyramid-c8cf2256655ee4b34ec501325b9016608b5cce5f.tar.gz
pyramid-c8cf2256655ee4b34ec501325b9016608b5cce5f.tar.bz2
pyramid-c8cf2256655ee4b34ec501325b9016608b5cce5f.zip
- Instead of invariably using ``webob.Request`` as the "request
factory" (e.g. in the ``Router`` class) and ``webob.Response`` and the "response factory" (e.g. in ``render_template_to_response``), allow both to be overridden via a ZCML utility hook. See the "Using ZCML Hooks" chapter of the documentation for more information.
-rw-r--r--CHANGES.txt12
-rw-r--r--docs/index.rst1
-rw-r--r--docs/narr/hooks.rst48
-rw-r--r--repoze/bfg/chameleon_genshi.py4
-rw-r--r--repoze/bfg/chameleon_text.py4
-rw-r--r--repoze/bfg/chameleon_zpt.py4
-rw-r--r--repoze/bfg/interfaces.py15
-rw-r--r--repoze/bfg/router.py9
-rw-r--r--repoze/bfg/tests/test_chameleon_genshi.py59
-rw-r--r--repoze/bfg/tests/test_chameleon_text.py43
-rw-r--r--repoze/bfg/tests/test_chameleon_zpt.py59
-rw-r--r--repoze/bfg/tests/test_router.py98
-rw-r--r--repoze/bfg/tests/test_view.py16
-rw-r--r--repoze/bfg/tests/test_wsgi.py29
-rw-r--r--repoze/bfg/tests/test_xslt.py22
-rw-r--r--repoze/bfg/view.py4
-rw-r--r--repoze/bfg/wsgi.py7
-rw-r--r--repoze/bfg/xslt.py4
18 files changed, 288 insertions, 150 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 9d17ca10e..2f5b14e84 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,15 @@
+After 0.6.2
+===========
+
+Features
+--------
+
+- Instead of invariably using ``webob.Request`` as the "request
+ factory" (e.g. in the ``Router`` class) and ``webob.Response`` and
+ the "response factory" (e.g. in ``render_template_to_response``),
+ allow both to be overridden via a ZCML utility hook. See the "Using
+ ZCML Hooks" chapter of the documentation for more information.
+
0.6.2 (2009-01-13)
==================
diff --git a/docs/index.rst b/docs/index.rst
index 13edb8a48..4df01341e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -36,6 +36,7 @@ Narrative documentation in chapter form explaining how to use
narr/events
narr/environment
narr/unittesting
+ narr/hooks
glossary
API documentation
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
new file mode 100644
index 000000000..009943e9e
--- /dev/null
+++ b/docs/narr/hooks.rst
@@ -0,0 +1,48 @@
+.. _hooks_chapter:
+
+Using ZCML Hooks
+================
+
+ZCML "hooks" can be used to influence the behavior of the
+:mod:`repoze.bfg` framework in various ways. This is an advanced
+topic; very few people will want or need to do any of these things.
+
+Changing the request factory
+----------------------------
+
+You may change the class used as the "request factory" from within the
+:mod:`repoze.bfg` ``Router`` class (the ``Router`` class turns the
+WSGI environment into a "request" object which is used ubiquitously
+throughout BFG). The default "request factory" is the class
+``webob.Request``. You may change it by placing the following ZCML in
+your ``configure.zcml`` file.
+
+.. code-block:: xml
+ :linenos:
+
+ <utility provides="repoze.bfg.interfaces.IRequestFactory"
+ component=".my.request.factory"/>
+
+Replace ``my.request.factory`` with the Python dotted name to the
+request factory you want to use.
+
+Changing the response factory
+-----------------------------
+
+You may change the class used as the "response factory" from within
+the :mod:`repoze.bfg` ``chameleon_zpt``, ``chameleon_genshi``,
+``chameleon_text`` (the ``render_template_to_response`` function used
+within each) and other various places where a Response object is
+constructed by :mod:`repoze.bfg`. The default "response factory" is
+the class ``webob.Response``. You may change it by placing the
+following ZCML in your ``configure.zcml`` file.
+
+.. code-block:: xml
+ :linenos:
+
+ <utility provides="repoze.bfg.interfaces.IResponseFactory"
+ component=".my.response.factory"/>
+
+Replace ``my.response.factory`` with the Python dotted name to the
+response factory you want to use.
+
diff --git a/repoze/bfg/chameleon_genshi.py b/repoze/bfg/chameleon_genshi.py
index 3d8472203..8c33dee14 100644
--- a/repoze/bfg/chameleon_genshi.py
+++ b/repoze/bfg/chameleon_genshi.py
@@ -6,6 +6,7 @@ from zope.interface import implements
from zope.interface import classProvides
from zope.deprecation import deprecated
+from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ISettings
from repoze.bfg.interfaces import ITemplateRenderer
from repoze.bfg.interfaces import ITemplateRendererFactory
@@ -70,5 +71,6 @@ def render_template_to_response(path, **kw):
renderer = renderer_from_cache(path, GenshiTemplateRenderer,
auto_reload=auto_reload)
result = renderer(**kw)
- return Response(result)
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ return response_factory(result)
diff --git a/repoze/bfg/chameleon_text.py b/repoze/bfg/chameleon_text.py
index e00106e5c..525957af1 100644
--- a/repoze/bfg/chameleon_text.py
+++ b/repoze/bfg/chameleon_text.py
@@ -5,6 +5,7 @@ from zope.component import queryUtility
from zope.interface import classProvides
from zope.interface import implements
+from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRenderer
from repoze.bfg.interfaces import ITemplateRendererFactory
from repoze.bfg.interfaces import ISettings
@@ -81,5 +82,6 @@ def render_template_to_response(path, **kw):
renderer = renderer_from_cache(path, TextTemplateRenderer,
auto_reload=auto_reload)
result = renderer(**kw)
- return Response(result)
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ return response_factory(result)
diff --git a/repoze/bfg/chameleon_zpt.py b/repoze/bfg/chameleon_zpt.py
index f7e9edadf..c3662770f 100644
--- a/repoze/bfg/chameleon_zpt.py
+++ b/repoze/bfg/chameleon_zpt.py
@@ -6,6 +6,7 @@ from zope.interface import classProvides
from zope.interface import implements
from zope.deprecation import deprecated
+from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRenderer
from repoze.bfg.interfaces import ITemplateRendererFactory
from repoze.bfg.interfaces import ISettings
@@ -72,5 +73,6 @@ def render_template_to_response(path, **kw):
renderer = renderer_from_cache(path, ZPTTemplateRenderer,
auto_reload=auto_reload)
result = renderer(**kw)
- return Response(result)
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ return response_factory(result)
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index 92e906e51..013267b7f 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -28,6 +28,13 @@ deprecated(
IRootPolicy = "repoze.bfg.interfaces:IRootFactory",
)
+class IRequestFactory(Interface):
+ """ A utility which generates a request factory """
+ def __call__(self):
+ """ Return a request factory (e.g. a callable that accepts an
+ environ and returns an object implementing IRequest,
+ e.g. ``webob.Request``)"""
+
class IRequest(Interface):
""" Request type interface attached to all request objects """
@@ -46,6 +53,14 @@ class IDELETERequest(IRequest):
class IHEADRequest(IRequest):
""" Request type interface attached to HEAD requests"""
+class IResponseFactory(Interface):
+ """ A utility which generates a response factory """
+ def __call__(self):
+ """ Return a response factory (e.g. a callable that returns an
+ object implementing IResponse, e.g. ``webob.Response``; it
+ should accept all the arguments that the webob.Response class
+ accepts)"""
+
class IResponse(Interface):
status = Attribute('WSGI status code of response')
headerlist = Attribute('List of response headers')
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index 8e1b998d8..755434870 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -21,6 +21,7 @@ from repoze.bfg.events import WSGIApplicationCreatedEvent
from repoze.bfg.interfaces import ILogger
from repoze.bfg.interfaces import ITraverserFactory
from repoze.bfg.interfaces import IRequest
+from repoze.bfg.interfaces import IRequestFactory
from repoze.bfg.interfaces import HTTP_METHOD_INTERFACES
from repoze.bfg.interfaces import IRouter
@@ -45,6 +46,11 @@ class Router(object):
def __init__(self, registry):
self.registry = registry
+ @property
+ def root_policy(self):
+ """ Backwards compatibility alias """
+ return self.registry.getUtility(IRootFactory)
+
def __call__(self, environ, start_response):
"""
Accept ``environ`` and ``start_response``; route requests to
@@ -54,7 +60,8 @@ class Router(object):
registry_manager.push(self.registry)
try:
- request = Request(environ)
+ request_factory = queryUtility(IRequestFactory, default=Request)
+ request = request_factory(environ)
directlyProvides(request, IRequest)
also = HTTP_METHOD_INTERFACES.get(request.method)
diff --git a/repoze/bfg/tests/test_chameleon_genshi.py b/repoze/bfg/tests/test_chameleon_genshi.py
index 3b0c05b34..9b210e1ad 100644
--- a/repoze/bfg/tests/test_chameleon_genshi.py
+++ b/repoze/bfg/tests/test_chameleon_genshi.py
@@ -1,13 +1,13 @@
import unittest
-from zope.component.testing import PlacelessSetup
+from zope.testing.cleanup import cleanUp
-class Base(PlacelessSetup):
+class Base(object):
def setUp(self):
- PlacelessSetup.setUp(self)
+ cleanUp()
def tearDown(self):
- PlacelessSetup.tearDown(self)
+ cleanUp()
def _zcmlConfigure(self):
import repoze.bfg.includes
@@ -20,13 +20,7 @@ class Base(PlacelessSetup):
here = os.path.abspath(os.path.dirname(__file__))
return os.path.join(here, 'fixtures', name)
-class GenshiTemplateRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class GenshiTemplateRendererTests(Base, unittest.TestCase):
def _getTargetClass(self):
from repoze.bfg.chameleon_genshi import GenshiTemplateRenderer
return GenshiTemplateRenderer
@@ -64,13 +58,7 @@ class GenshiTemplateRendererTests(unittest.TestCase, Base):
self.assertEqual(result,
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
-class RenderTemplateTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_genshi import render_template
return render_template
@@ -83,13 +71,7 @@ class RenderTemplateTests(unittest.TestCase, Base):
self.assertEqual(result,
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
-class RenderTemplateToResponseTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateToResponseTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_genshi import render_template_to_response
return render_template_to_response
@@ -105,13 +87,20 @@ class RenderTemplateToResponseTests(unittest.TestCase, Base):
self.assertEqual(result.status, '200 OK')
self.assertEqual(len(result.headerlist), 2)
-class GetRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
+ def test_iresponsefactory_override(self):
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ from webob import Response
+ class Response2(Response):
+ pass
+ from repoze.bfg.interfaces import IResponseFactory
+ gsm.registerUtility(Response2, IResponseFactory)
+ minimal = self._getTemplatePath('minimal.genshi')
+ render = self._getFUT()
+ result = render(minimal)
+ self.failUnless(isinstance(result, Response2))
+class GetRendererTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_genshi import get_renderer
return get_renderer
@@ -160,13 +149,7 @@ class GetRendererTests(unittest.TestCase, Base):
self.failUnless(result is utility)
-class GetTemplateTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class GetTemplateTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_genshi import get_template
return get_template
diff --git a/repoze/bfg/tests/test_chameleon_text.py b/repoze/bfg/tests/test_chameleon_text.py
index f61cfe963..992957d0e 100644
--- a/repoze/bfg/tests/test_chameleon_text.py
+++ b/repoze/bfg/tests/test_chameleon_text.py
@@ -20,13 +20,7 @@ class Base:
here = os.path.abspath(os.path.dirname(__file__))
return os.path.join(here, 'fixtures', name)
-class TextTemplateRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class TextTemplateRendererTests(Base, unittest.TestCase):
def _getTargetClass(self):
from repoze.bfg.chameleon_text import TextTemplateRenderer
return TextTemplateRenderer
@@ -70,13 +64,7 @@ class TextTemplateRendererTests(unittest.TestCase, Base):
self.failUnless(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
-class RenderTemplateTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_text import render_template
return render_template
@@ -89,13 +77,7 @@ class RenderTemplateTests(unittest.TestCase, Base):
self.failUnless(isinstance(result, str))
self.assertEqual(result, 'Hello.\n')
-class RenderTemplateToResponseTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateToResponseTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_text import render_template_to_response
return render_template_to_response
@@ -111,13 +93,20 @@ class RenderTemplateToResponseTests(unittest.TestCase, Base):
self.assertEqual(result.status, '200 OK')
self.assertEqual(len(result.headerlist), 2)
-class GetRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
+ def test_iresponsefactory_override(self):
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ from webob import Response
+ class Response2(Response):
+ pass
+ from repoze.bfg.interfaces import IResponseFactory
+ gsm.registerUtility(Response2, IResponseFactory)
+ minimal = self._getTemplatePath('minimal.txt')
+ render = self._getFUT()
+ result = render(minimal)
+ self.failUnless(isinstance(result, Response2))
+class GetRendererTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_text import get_renderer
return get_renderer
diff --git a/repoze/bfg/tests/test_chameleon_zpt.py b/repoze/bfg/tests/test_chameleon_zpt.py
index 995dd92e1..088930069 100644
--- a/repoze/bfg/tests/test_chameleon_zpt.py
+++ b/repoze/bfg/tests/test_chameleon_zpt.py
@@ -1,13 +1,13 @@
import unittest
-from zope.component.testing import PlacelessSetup
+from zope.testing.cleanup import cleanUp
-class Base(PlacelessSetup):
+class Base(object):
def setUp(self):
- PlacelessSetup.setUp(self)
+ cleanUp()
def tearDown(self):
- PlacelessSetup.tearDown(self)
+ cleanUp()
def _zcmlConfigure(self):
import repoze.bfg.includes
@@ -20,13 +20,7 @@ class Base(PlacelessSetup):
here = os.path.abspath(os.path.dirname(__file__))
return os.path.join(here, 'fixtures', name)
-class ZPTTemplateRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class ZPTTemplateRendererTests(Base, unittest.TestCase):
def _getTargetClass(self):
from repoze.bfg.chameleon_zpt import ZPTTemplateRenderer
return ZPTTemplateRenderer
@@ -65,13 +59,7 @@ class ZPTTemplateRendererTests(unittest.TestCase, Base):
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
-class RenderTemplateTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_zpt import render_template
return render_template
@@ -85,13 +73,7 @@ class RenderTemplateTests(unittest.TestCase, Base):
self.assertEqual(result,
'<div xmlns="http://www.w3.org/1999/xhtml">\n</div>')
-class RenderTemplateToResponseTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class RenderTemplateToResponseTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_zpt import render_template_to_response
return render_template_to_response
@@ -108,13 +90,20 @@ class RenderTemplateToResponseTests(unittest.TestCase, Base):
self.assertEqual(result.status, '200 OK')
self.assertEqual(len(result.headerlist), 2)
-class GetRendererTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
+ def test_iresponsefactory_override(self):
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ from webob import Response
+ class Response2(Response):
+ pass
+ from repoze.bfg.interfaces import IResponseFactory
+ gsm.registerUtility(Response2, IResponseFactory)
+ minimal = self._getTemplatePath('minimal.pt')
+ render = self._getFUT()
+ result = render(minimal)
+ self.failUnless(isinstance(result, Response2))
+class GetRendererTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_zpt import get_renderer
return get_renderer
@@ -162,13 +151,7 @@ class GetRendererTests(unittest.TestCase, Base):
result = get('foo')
self.failUnless(result is utility)
-class GetTemplateTests(unittest.TestCase, Base):
- def setUp(self):
- Base.setUp(self)
-
- def tearDown(self):
- Base.tearDown(self)
-
+class GetTemplateTests(Base, unittest.TestCase):
def _getFUT(self):
from repoze.bfg.chameleon_zpt import get_template
return get_template
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 298065d9b..e0d27b332 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -1,17 +1,15 @@
import unittest
-from zope.component.testing import PlacelessSetup
+from zope.testing.cleanup import cleanUp
-class RouterTests(unittest.TestCase, PlacelessSetup):
+class RouterTests(unittest.TestCase):
def setUp(self):
- PlacelessSetup.setUp(self)
+ cleanUp()
def tearDown(self):
- PlacelessSetup.tearDown(self)
+ cleanUp()
def _registerLogger(self):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import ILogger
class Logger:
def __init__(self):
@@ -20,12 +18,12 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self.messages.append(msg)
debug = info
logger = Logger()
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerUtility(logger, ILogger, name='repoze.bfg.debug')
return logger
def _registerSettings(self, **kw):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import ISettings
class Settings:
def __init__(self, **kw):
@@ -34,41 +32,47 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
defaultkw = {'debug_authorization':False, 'debug_notfound':False}
defaultkw.update(kw)
settings = Settings(**defaultkw)
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerUtility(settings, ISettings)
def _registerTraverserFactory(self, app, name, *for_):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import ITraverserFactory
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerAdapter(app, for_, ITraverserFactory, name)
def _registerView(self, app, name, *for_):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import IView
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerAdapter(app, for_, IView, name)
def _registerPermission(self, permission, name, *for_):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import IViewPermission
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerAdapter(permission, for_, IViewPermission, name)
def _registerSecurityPolicy(self, secpol):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import ISecurityPolicy
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerUtility(secpol, ISecurityPolicy)
- def _registerEventListener(self, listener, iface):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
+ def _registerEventListener(self, iface):
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ L = []
+ def listener(event):
+ L.append(event)
gsm.registerHandler(listener, (iface,))
+ return L
def _registerRootFactory(self, root_factory):
- import zope.component
- gsm = zope.component.getGlobalSiteManager()
from repoze.bfg.interfaces import IRootFactory
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
gsm.registerUtility(root_factory, IRootFactory)
def _getTargetClass(self):
@@ -424,14 +428,8 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerView(view, '', None, None)
from repoze.bfg.interfaces import INewRequest
from repoze.bfg.interfaces import INewResponse
- request_events = []
- response_events = []
- def handle_request(event):
- request_events.append(event)
- def handle_response(event):
- response_events.append(event)
- self._registerEventListener(handle_request, INewRequest)
- self._registerEventListener(handle_response, INewResponse)
+ request_events = self._registerEventListener(INewRequest)
+ response_events = self._registerEventListener(INewResponse)
self._registerRootFactory(rootfactory)
router = self._makeOne(None)
start_response = DummyStartResponse()
@@ -458,10 +456,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerRootFactory(rootfactory)
router = self._makeOne(None)
start_response = DummyStartResponse()
- request_events = []
- def handle_request(event):
- request_events.append(event)
- self._registerEventListener(handle_request, INewRequest)
+ request_events = self._registerEventListener(INewRequest)
result = router(environ, start_response)
request = request_events[0].request
self.failUnless(IPOSTRequest.providedBy(request))
@@ -485,22 +480,45 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerRootFactory(rootfactory)
router = self._makeOne(None)
start_response = DummyStartResponse()
- request_events = []
- def handle_request(event):
- request_events.append(event)
- self._registerEventListener(handle_request, INewRequest)
+ request_events = self._registerEventListener(INewRequest)
result = router(environ, start_response)
request = request_events[0].request
self.failUnless(IPUTRequest.providedBy(request))
self.failIf(IPOSTRequest.providedBy(request))
self.failUnless(IRequest.providedBy(request))
+
+ def test_call_irequestfactory_override(self):
+ from repoze.bfg.interfaces import INewRequest
+ from repoze.bfg.interfaces import IRequestFactory
+ from webob import Request
+ class Request2(Request):
+ pass
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(Request2, IRequestFactory)
+ rootfactory = make_rootfactory(None)
+ context = DummyContext()
+ traversalfactory = make_traversal_factory(context, '', [])
+ response = DummyResponse()
+ response.app_iter = ['Hello world']
+ view = make_view(response)
+ environ = self._makeEnviron()
+ self._registerTraverserFactory(traversalfactory, '', None)
+ self._registerView(view, '', None, None)
+ self._registerRootFactory(rootfactory)
+ router = self._makeOne(None)
+ start_response = DummyStartResponse()
+ request_events = self._registerEventListener(INewRequest)
+ result = router(environ, start_response)
+ request = request_events[0].request
+ self.failUnless(isinstance(request, Request2))
-class MakeAppTests(unittest.TestCase, PlacelessSetup):
+class MakeAppTests(unittest.TestCase):
def setUp(self):
- PlacelessSetup.setUp(self)
+ cleanUp()
def tearDown(self):
- PlacelessSetup.tearDown(self)
+ cleanUp()
def _callFUT(self, *arg, **kw):
from repoze.bfg.router import make_app
diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py
index 389c00cc5..6f16da28e 100644
--- a/repoze/bfg/tests/test_view.py
+++ b/repoze/bfg/tests/test_view.py
@@ -468,6 +468,22 @@ class TestStaticView(unittest.TestCase, BaseTest):
filedata = open(os.path.join(static_dir, '__init__.py')).read()
self.assertEqual(result, filedata)
+ def test_it_with_alternate_iresponsefactory(self):
+ view = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.subpath = ['__init__.py']
+ request.environ = self._makeEnviron()
+ from repoze.bfg.interfaces import IResponseFactory
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ from webob import Response
+ class Response2(Response):
+ pass
+ gsm.registerUtility(Response2, IResponseFactory)
+ response = view(context, request)
+ self.failUnless(isinstance(response, Response2))
+
class DummyContext:
pass
diff --git a/repoze/bfg/tests/test_wsgi.py b/repoze/bfg/tests/test_wsgi.py
index 4c36850b6..ac02ec49f 100644
--- a/repoze/bfg/tests/test_wsgi.py
+++ b/repoze/bfg/tests/test_wsgi.py
@@ -1,6 +1,13 @@
import unittest
+from zope.testing.cleanup import cleanUp
class WSGIAppTests(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def test_decorator(self):
body = 'Unauthorized'
headerlist = [ ('Content-Type', 'text/plain'),
@@ -18,6 +25,28 @@ class WSGIAppTests(unittest.TestCase):
self.assertEqual(response.headerlist, headerlist)
self.assertEqual(response.app_iter, [body])
+ def test_decorator_alternate_iresponsefactory(self):
+ body = 'Unauthorized'
+ headerlist = [ ('Content-Type', 'text/plain'),
+ ('Content-Length', len(body)) ]
+ status = '401 Unauthorized'
+ def real_wsgiapp(environ, start_response):
+ start_response(status, headerlist)
+ return [body]
+ from repoze.bfg.wsgi import wsgiapp
+ wrapped = wsgiapp(real_wsgiapp)
+ context = DummyContext()
+ request = DummyRequest({})
+ from repoze.bfg.interfaces import IResponseFactory
+ from zope.component import getGlobalSiteManager
+ from webob import Response
+ class Response2(Response):
+ pass
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(Response2, IResponseFactory)
+ response = wrapped(context, request)
+ self.failUnless(isinstance(response, Response2))
+
def test_decorator_startresponse_uncalled(self):
body = 'Unauthorized'
headerlist = [ ('Content-Type', 'text/plain'),
diff --git a/repoze/bfg/tests/test_xslt.py b/repoze/bfg/tests/test_xslt.py
index 3755ad8a5..38e693937 100644
--- a/repoze/bfg/tests/test_xslt.py
+++ b/repoze/bfg/tests/test_xslt.py
@@ -137,6 +137,28 @@ class RenderTransformToResponseTests(Base, unittest.TestCase):
self.assertEqual(len(result.headerlist), 2)
self.assertEqual(queryUtility(INodeTemplateRenderer, minimal), utility)
+ def test_alternate_iresponse_factory(self):
+ self._zcmlConfigure()
+ from repoze.bfg.interfaces import IResponseFactory
+ from zope.component import getGlobalSiteManager
+ gsm = getGlobalSiteManager()
+ from webob import Response
+ class Response2(Response):
+ pass
+ gsm.registerUtility(Response2, IResponseFactory)
+ from zope.component import getGlobalSiteManager
+ from repoze.bfg.xslt import XSLTemplateRenderer
+ from repoze.bfg.interfaces import INodeTemplateRenderer
+ minimal = self._getTemplatePath('minimal.xsl')
+ utility = XSLTemplateRenderer(minimal)
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(utility, INodeTemplateRenderer, name=minimal)
+ from lxml import etree
+ info = etree.Element("info")
+ result = self._callFUT(minimal, node=info)
+ self.failUnless(isinstance(result, Response2))
+
+
class RenderTransformTests(Base, unittest.TestCase):
def _callFUT(self, path, node):
from repoze.bfg.xslt import render_transform
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 39829af62..3f9216b0d 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -4,6 +4,7 @@ from webob import Response
from zope.component import queryMultiAdapter
from zope.component import queryUtility
+from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ISecurityPolicy
from repoze.bfg.interfaces import IViewPermission
from repoze.bfg.interfaces import IView
@@ -154,7 +155,8 @@ class static(object):
ecopy['SCRIPT_NAME'] = ''
body = self.app(ecopy, catch_start_response)
status, headers, exc_info = caught
- response = Response()
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ response = response_factory()
response.app_iter = body
response.status = status
response.headerlist = headers
diff --git a/repoze/bfg/wsgi.py b/repoze/bfg/wsgi.py
index 149273c27..93b2c143b 100644
--- a/repoze/bfg/wsgi.py
+++ b/repoze/bfg/wsgi.py
@@ -1,3 +1,7 @@
+from zope.component import queryUtility
+
+from repoze.bfg.interfaces import IResponseFactory
+
from webob import Response
try:
from functools import wraps
@@ -37,7 +41,8 @@ def wsgiapp(wrapped):
body = wrapped(environ, catch_start_response)
if caught:
status, headers, exc_info = caught
- response = Response()
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ response = response_factory()
response.app_iter = body
response.status = status
response.headerlist = headers
diff --git a/repoze/bfg/xslt.py b/repoze/bfg/xslt.py
index 8c03dc493..7dae7ca8e 100644
--- a/repoze/bfg/xslt.py
+++ b/repoze/bfg/xslt.py
@@ -12,6 +12,7 @@ from zope.interface import implements
from repoze.bfg.path import caller_path
from repoze.bfg.interfaces import INodeTemplateRenderer
+from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRendererFactory
def get_transform(path, node):
@@ -46,7 +47,8 @@ def render_transform_to_response(path, node, **kw):
the lxml node at ``node`` and return a Response object."""
path = caller_path(path)
result = render_transform(path, node, **kw)
- return Response(result)
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ return response_factory(result)
class XSLTemplateRenderer(object):
classProvides(ITemplateRendererFactory)