CONTRIBUTORS.txt | ●●●●● patch | view | raw | blame | history | |
docs/api/response.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/hooks.rst | ●●●●● patch | view | raw | blame | history | |
pyramid/response.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_response.py | ●●●●● patch | view | raw | blame | history |
CONTRIBUTORS.txt
@@ -144,3 +144,5 @@ - Christoph Zwerschke, 2011/06/07 - Shane Hathaway, 2011/07/22 - Manuel Hermann, 2011/07/11 docs/api/response.rst
@@ -9,3 +9,8 @@ :members: :inherited-members: Functions ~~~~~~~~~ .. autofunction:: response_adapter docs/narr/hooks.rst
@@ -537,7 +537,8 @@ It is possible to control how Pyramid treats the result of calling a view callable on a per-type basis by using a hook involving :meth:`pyramid.config.Configurator.add_response_adapter`. :meth:`pyramid.config.Configurator.add_response_adapter` or the :class:`~pyramid.response.response_adapter` decorator. .. note:: This feature is new as of Pyramid 1.1. @@ -574,6 +575,20 @@ config.add_response_adapter(string_response_adapter, str) The above example using the :class:`~pyramid.response.response_adapter` decorator: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.response import response_adapter @response_adapter(str) def string_response_adapter(s): response = Response(s) return response Likewise, if you want to be able to return a simplified kind of response object from view callables, you can use the IResponse hook to register an adapter to the more complex IResponse interface: pyramid/response.py
@@ -1,3 +1,5 @@ import venusian from webob import Response as _Response from zope.interface import implements from pyramid.interfaces import IResponse @@ -5,3 +7,57 @@ class Response(_Response): implements(IResponse) class response_adapter(object): """ Decorator activated via a :term:`scan` which treats the function being decorated as a response adapter for the set of types or interfaces passed as ``*types_or_ifaces`` to the decorator constructor. For example: .. code-block:: python from pyramid.response import Response from pyramid.response import response_adapter @response_adapter(int) def myadapter(i): return Response(status=i) More than one type or interface can be passed as a constructor argument. The decorated response adapter will be called for each type or interface. .. code-block:: python import json from pyramid.response import Response from pyramid.response import response_adapter @response_adapter(dict, list) def myadapter(ob): return Response(json.dumps(ob)) This method will have no effect until a :term:`scan` is performed agains the package or module which contains it, ala: .. code-block:: python from pyramid.config import Configurator config = Configurator() config.scan('somepackage_containing_adapters') """ venusian = venusian # for unit testing def __init__(self, *types_or_ifaces): self.types_or_ifaces = types_or_ifaces def register(self, scanner, name, wrapped): config = scanner.config for type_or_iface in self.types_or_ifaces: config.add_response_adapter(wrapped, type_or_iface) def __call__(self, wrapped): self.venusian.attach(wrapped, self.register, category='pyramid') return wrapped pyramid/tests/test_response.py
@@ -1,4 +1,5 @@ import unittest from pyramid import testing class TestResponse(unittest.TestCase): def _getTargetClass(self): @@ -15,3 +16,66 @@ inst = self._getTargetClass()() self.assertTrue(IResponse.providedBy(inst)) class Dummy(object): pass class DummyConfigurator(object): def __init__(self): self.adapters = [] def add_response_adapter(self, wrapped, type_or_iface): self.adapters.append((wrapped, type_or_iface)) class DummyVenusian(object): def __init__(self): self.attached = [] def attach(self, wrapped, fn, category=None): self.attached.append((wrapped, fn, category)) class TestResponseAdapter(unittest.TestCase): def setUp(self): registry = Dummy() self.config = testing.setUp(registry=registry) self.config.begin() def tearDown(self): self.config.end() def _makeOne(self, *types_or_ifaces): from pyramid.response import response_adapter return response_adapter(*types_or_ifaces) def test_register_single(self): from zope.interface import Interface class IFoo(Interface): pass dec = self._makeOne(IFoo) def foo(): pass config = DummyConfigurator() scanner = Dummy() scanner.config = config dec.register(scanner, None, foo) self.assertEqual(config.adapters, [(foo, IFoo)]) def test_register_multi(self): from zope.interface import Interface class IFoo(Interface): pass class IBar(Interface): pass dec = self._makeOne(IFoo, IBar) def foo(): pass config = DummyConfigurator() scanner = Dummy() scanner.config = config dec.register(scanner, None, foo) self.assertEqual(config.adapters, [(foo, IFoo), (foo, IBar)]) def test___call__(self): from zope.interface import Interface class IFoo(Interface): pass dec = self._makeOne(IFoo) dummy_venusian = DummyVenusian() dec.venusian = dummy_venusian def foo(): pass dec(foo) self.assertEqual(dummy_venusian.attached, [(foo, dec.register, 'pyramid')])