From 88c11a8f09d6e9749a705cb62caa945c496e84e9 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Fri, 26 Dec 2014 00:30:25 -0800 Subject: Refactored how `ResponseClass` is used so it can be overridden --- pyramid/renderers.py | 7 +++---- pyramid/request.py | 10 +++++----- pyramid/util.py | 21 +++++++++++++++++++++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/pyramid/renderers.py b/pyramid/renderers.py index e647ebacf..3d5390840 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -10,7 +10,6 @@ from zope.interface.registry import Components from pyramid.interfaces import ( IJSONAdapter, IRendererFactory, - IResponseFactory, IRendererInfo, ) @@ -19,6 +18,8 @@ from pyramid.compat import ( text_type, ) +from pyramid.util import _get_response_factory + from pyramid.decorator import reify from pyramid.events import BeforeRender @@ -448,9 +449,7 @@ class RendererHelper(object): if response is None: # request is None or request is not a pyramid.response.Response registry = self.registry - response_factory = registry.queryUtility(IResponseFactory, - default=Response) - + response_factory = _get_response_factory(registry, request) response = response_factory() if result is not None: diff --git a/pyramid/request.py b/pyramid/request.py index bc2889310..b66b8926c 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -10,7 +10,6 @@ from pyramid.interfaces import ( IRequest, IResponse, ISessionFactory, - IResponseFactory, ) from pyramid.compat import ( @@ -27,7 +26,10 @@ from pyramid.security import ( AuthorizationAPIMixin, ) from pyramid.url import URLMethodsMixin -from pyramid.util import InstancePropertyMixin +from pyramid.util import ( + InstancePropertyMixin, + _get_response_factory, +) class TemplateContext(object): pass @@ -214,9 +216,7 @@ class Request( right" attributes (e.g. by calling ``request.response.set_cookie()``) within a view that uses a renderer. Mutations to this response object will be preserved in the response sent to the client.""" - registry = self.registry - response_factory = registry.queryUtility(IResponseFactory, - default=Response) + response_factory = _get_response_factory(self.registry, self) return response_factory() def is_response(self, ob): diff --git a/pyramid/util.py b/pyramid/util.py index 6de53d559..ee642164a 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -15,6 +15,10 @@ from pyramid.exceptions import ( CyclicDependencyError, ) +from pyramid.interfaces import ( + IResponseFactory, + ) + from pyramid.compat import ( iteritems_, is_nonstr_iter, @@ -25,6 +29,7 @@ from pyramid.compat import ( ) from pyramid.interfaces import IActionInfo +from pyramid.response import Response from pyramid.path import DottedNameResolver as _DottedNameResolver class DottedNameResolver(_DottedNameResolver): @@ -551,3 +556,19 @@ def action_method(wrapped): wrapper.__docobj__ = wrapped return wrapper +def _get_response_factory(registry, request=None): + """ Obtain a :class: `pyramid.response.Response` using the + ``request.ResponseClass`` property if available. + """ + # Request is `None` or does not have a `ResponseClass` + if hasattr(request, 'ResponseClass'): + response_class = request.ResponseClass + else: + response_class = Response + + response_factory = registry.queryUtility( + IResponseFactory, + default=response_class + ) + + return response_factory -- cgit v1.2.3 From 367ffec92bd502075e0f2f827f4b9d9b3caea748 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Fri, 26 Dec 2014 00:44:44 -0800 Subject: Add test to show usage of custom response class --- pyramid/tests/test_config/test_init.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py index 1e58e4d0f..c9eaf7c27 100644 --- a/pyramid/tests/test_config/test_init.py +++ b/pyramid/tests/test_config/test_init.py @@ -546,6 +546,36 @@ class ConfiguratorTests(unittest.TestCase): utility = reg.getUtility(IRequestFactory) self.assertEqual(utility, factory) + def test_setup_registry_request_factory_custom_response_class(self): + from pyramid.registry import Registry + from pyramid.interfaces import IRequestFactory + from pyramid.request import Request + + class MyResponse(object): + pass + + class MyRequest(Request): + ResponseClass = MyResponse + + reg = Registry() + config = self._makeOne(reg) + factory = MyRequest({ + 'PATH_INFO': '/', + 'wsgi.url_scheme': 'http', + 'HTTP_HOST': 'localhost', + 'SERVER_PROTOCOL': '1.0', + }) + factory.registry = reg + + config.setup_registry(request_factory=factory) + self.assertEqual(reg.queryUtility(IRequestFactory), None) + config.commit() + utility = reg.getUtility(IRequestFactory) + self.assertEqual(utility, factory) + + new_response = factory.response + self.assertTrue(isinstance(new_response, MyResponse)) + def test_setup_registry_request_factory_dottedname(self): from pyramid.registry import Registry from pyramid.interfaces import IRequestFactory -- cgit v1.2.3 From c0a01d1a49c9a02b1aa7266301fd64fb679e1d53 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Fri, 26 Dec 2014 04:17:42 -0800 Subject: Added 2 more tests directly to the util function --- pyramid/tests/test_util.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index a18fa8d16..c9c48aede 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -619,6 +619,33 @@ class TestActionInfo(unittest.TestCase): "Line 0 of file filename:\n linerepr ") +class TestGetResponseFactory(unittest.TestCase): + def test_no_request(self): + from pyramid.util import _get_response_factory + from pyramid.registry import Registry + from pyramid.response import Response + + registry = Registry() + factory = _get_response_factory(registry) + self.assertEqual(factory, Response) + + def test_with_request(self): + from pyramid.util import _get_response_factory + from pyramid.registry import Registry + from pyramid.request import Request + + class MyResponse(object): + pass + + class MyRequest(Request): + ResponseClass = MyResponse + registry = Registry() + + request = MyRequest({}) + factory = _get_response_factory(registry, request) + self.assertEqual(factory, MyResponse) + + def dummyfunc(): pass class Dummy(object): -- cgit v1.2.3 From e21662924a296f391fdbbf725fb79e409bca59f4 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Fri, 26 Dec 2014 05:11:51 -0800 Subject: pass proper registry --- pyramid/tests/test_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index c9c48aede..0ebbd80a2 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -642,7 +642,7 @@ class TestGetResponseFactory(unittest.TestCase): registry = Registry() request = MyRequest({}) - factory = _get_response_factory(registry, request) + factory = _get_response_factory(request.registry, request) self.assertEqual(factory, MyResponse) -- cgit v1.2.3 From 1236dec0dcfd916bca4e233587f86baa8d2418a8 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 00:18:23 -0800 Subject: Add the `set_response_factory` API --- docs/narr/hooks.rst | 62 +++++++++++++++++++++++++++++ pyramid/config/__init__.py | 16 +++++++- pyramid/config/factories.py | 27 +++++++++++++ pyramid/tests/test_config/test_factories.py | 15 +++++++ pyramid/tests/test_config/test_init.py | 12 ++++++ 5 files changed, 130 insertions(+), 2 deletions(-) diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4da36e730..f557527bb 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -354,6 +354,68 @@ We attach and cache an object named ``extra`` to the ``request`` object. .. _beforerender_event: +.. index:: + single: response factory + +.. _changing_the_response_factory: + +Changing the Response Factory +---------------------------- + +Whenever :app:`Pyramid` returns a response from a view it creates a +:term:`response` object. By default, an instance of the +:class:`pyramid.response.Response` class is created to represent the response +object. + +The class (aka "factory") that :app:`Pyramid` uses to create a response object +instance can be changed by passing a ``response_factory`` argument to the +constructor of the :term:`configurator`. This argument can be either a +callable or a :term:`dotted Python name` representing a callable. + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + class MyResponse(Response): + pass + + config = Configurator(response_factory=MyResponse) + +If you're doing imperative configuration, and you'd rather do it after you've +already constructed a :term:`configurator` it can also be registered via the +:meth:`pyramid.config.Configurator.set_response_factory` method: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.response import Response + + class MyResponse(Response): + pass + + config = Configurator() + config.set_response_factory(MyRequest) + +If you are already using a custom ```request_factory`` you can also set the +``ResponseClass`` on your :class:`pyramid.request.Request`: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.response import Response + from pyramid.request import Request + + class MyResponse(Response): + pass + + class MyRequest(Request): + ResponseClass = MyResponse + + config = Configurator() + Using The Before Render Event ----------------------------- diff --git a/pyramid/config/__init__.py b/pyramid/config/__init__.py index cfa35ec6c..2ab654b9a 100644 --- a/pyramid/config/__init__.py +++ b/pyramid/config/__init__.py @@ -179,6 +179,11 @@ class Configurator( See :ref:`changing_the_request_factory`. By default it is ``None``, which means use the default request factory. + If ``response_factory`` is passed, it should be a :term:`response + factory` implementation or a :term:`dotted Python name` to the same. + See :ref:`changing_the_response_factory`. By default it is ``None``, + which means use the default response factory. + If ``default_permission`` is passed, it should be a :term:`permission` string to be used as the default permission for all view configuration registrations performed against this @@ -190,7 +195,7 @@ class Configurator( configurations which do not explicitly declare a permission will always be executable by entirely anonymous users (any authorization policy in effect is ignored). - + .. seealso:: See also :ref:`setting_a_default_permission`. @@ -254,6 +259,7 @@ class Configurator( .. versionadded:: 1.6 The ``root_package`` argument. + The ``response_factory`` argument. """ manager = manager # for testing injection venusian = venusian # for testing injection @@ -276,6 +282,7 @@ class Configurator( debug_logger=None, locale_negotiator=None, request_factory=None, + response_factory=None, default_permission=None, session_factory=None, default_view_mapper=None, @@ -310,6 +317,7 @@ class Configurator( debug_logger=debug_logger, locale_negotiator=locale_negotiator, request_factory=request_factory, + response_factory=response_factory, default_permission=default_permission, session_factory=session_factory, default_view_mapper=default_view_mapper, @@ -325,6 +333,7 @@ class Configurator( debug_logger=None, locale_negotiator=None, request_factory=None, + response_factory=None, default_permission=None, session_factory=None, default_view_mapper=None, @@ -412,6 +421,9 @@ class Configurator( if request_factory: self.set_request_factory(request_factory) + if response_factory: + self.set_response_factory(response_factory) + if default_permission: self.set_default_permission(default_permission) @@ -469,7 +481,7 @@ class Configurator( _registry.registerSelfAdapter = registerSelfAdapter # API - + def _get_introspector(self): introspector = getattr(self.registry, 'introspector', _marker) if introspector is _marker: diff --git a/pyramid/config/factories.py b/pyramid/config/factories.py index 5ce1081c6..d7a48ba93 100644 --- a/pyramid/config/factories.py +++ b/pyramid/config/factories.py @@ -4,6 +4,7 @@ from zope.interface import implementer from pyramid.interfaces import ( IDefaultRootFactory, IRequestFactory, + IResponseFactory, IRequestExtensions, IRootFactory, ISessionFactory, @@ -96,6 +97,32 @@ class FactoriesConfiguratorMixin(object): intr['factory'] = factory self.action(IRequestFactory, register, introspectables=(intr,)) + @action_method + def set_response_factory(self, factory): + """ The object passed as ``factory`` should be an object (or a + :term:`dotted Python name` which refers to an object) which + will be used by the :app:`Pyramid` as the default response + objects. This factory object must have the same + methods and attributes as the + :class:`pyramid.request.Response` class. + + .. note:: + + Using the ``response_factory`` argument to the + :class:`pyramid.config.Configurator` constructor + can be used to achieve the same purpose. + """ + factory = self.maybe_dotted(factory) + + def register(): + self.registry.registerUtility(factory, IResponseFactory) + + intr = self.introspectable('response factory', None, + self.object_description(factory), + 'response factory') + intr['factory'] = factory + self.action(IResponseFactory, register, introspectables=(intr,)) + @action_method def add_request_method(self, callable=None, diff --git a/pyramid/tests/test_config/test_factories.py b/pyramid/tests/test_config/test_factories.py index 6e679397f..c6785d4a5 100644 --- a/pyramid/tests/test_config/test_factories.py +++ b/pyramid/tests/test_config/test_factories.py @@ -23,6 +23,21 @@ class TestFactoriesMixin(unittest.TestCase): self.assertEqual(config.registry.getUtility(IRequestFactory), dummyfactory) + def test_set_response_factory(self): + from pyramid.interfaces import IResponseFactory + config = self._makeOne(autocommit=True) + factory = object() + config.set_response_factory(factory) + self.assertEqual(config.registry.getUtility(IResponseFactory), factory) + + def test_set_response_factory_dottedname(self): + from pyramid.interfaces import IResponseFactory + config = self._makeOne(autocommit=True) + config.set_response_factory( + 'pyramid.tests.test_config.dummyfactory') + self.assertEqual(config.registry.getUtility(IResponseFactory), + dummyfactory) + def test_set_root_factory(self): from pyramid.interfaces import IRootFactory config = self._makeOne() diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py index c9eaf7c27..8fa6be011 100644 --- a/pyramid/tests/test_config/test_init.py +++ b/pyramid/tests/test_config/test_init.py @@ -546,6 +546,18 @@ class ConfiguratorTests(unittest.TestCase): utility = reg.getUtility(IRequestFactory) self.assertEqual(utility, factory) + def test_setup_registry_response_factory(self): + from pyramid.registry import Registry + from pyramid.interfaces import IResponseFactory + reg = Registry() + config = self._makeOne(reg) + factory = object() + config.setup_registry(response_factory=factory) + self.assertEqual(reg.queryUtility(IResponseFactory), None) + config.commit() + utility = reg.getUtility(IResponseFactory) + self.assertEqual(utility, factory) + def test_setup_registry_request_factory_custom_response_class(self): from pyramid.registry import Registry from pyramid.interfaces import IRequestFactory -- cgit v1.2.3 From e8a666655b5365a0adde32f2bd387b0d42690384 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 00:23:18 -0800 Subject: basic docs cleanup --- docs/glossary.rst | 3 +++ docs/narr/hooks.rst | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 01300a0be..05ff7c114 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -16,6 +16,9 @@ Glossary An object which, provided a :term:`WSGI` environment as a single positional argument, returns a Pyramid-compatible request. + response factory + An object which returns a Pyramid-compatible response. + response An object returned by a :term:`view callable` that represents response data returned to the requesting user agent. It must implement the diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f557527bb..4702c09b0 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -360,7 +360,7 @@ We attach and cache an object named ``extra`` to the ``request`` object. .. _changing_the_response_factory: Changing the Response Factory ----------------------------- +------------------------------- Whenever :app:`Pyramid` returns a response from a view it creates a :term:`response` object. By default, an instance of the -- cgit v1.2.3 From 807e941787e157db882fcd95e13f5cafb7ebde7f Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 13:33:39 -0800 Subject: Added a version added flag --- docs/narr/hooks.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4702c09b0..689ce9dc2 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -362,6 +362,8 @@ We attach and cache an object named ``extra`` to the ``request`` object. Changing the Response Factory ------------------------------- +.. versionadded:: 1.6 + Whenever :app:`Pyramid` returns a response from a view it creates a :term:`response` object. By default, an instance of the :class:`pyramid.response.Response` class is created to represent the response -- cgit v1.2.3 From 32cb805132e8149a276a8c65fdfa961384e8254e Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 15:03:56 -0800 Subject: Mkae the response factory a factory that takes a request --- docs/glossary.rst | 3 ++- docs/narr/hooks.rst | 29 ++++++-------------------- pyramid/renderers.py | 4 ++-- pyramid/request.py | 4 ++-- pyramid/testing.py | 10 +++++---- pyramid/tests/test_config/test_factories.py | 2 +- pyramid/tests/test_config/test_init.py | 32 +---------------------------- pyramid/tests/test_renderers.py | 9 ++++++-- pyramid/tests/test_testing.py | 4 +++- pyramid/tests/test_util.py | 26 +++++------------------ pyramid/util.py | 13 ++++-------- 11 files changed, 39 insertions(+), 97 deletions(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 05ff7c114..38133f68f 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -17,7 +17,8 @@ Glossary positional argument, returns a Pyramid-compatible request. response factory - An object which returns a Pyramid-compatible response. + An object which, provied a :term:`request` as a single positional + argument, returns a Pyramid-compatible response. response An object returned by a :term:`view callable` that represents response diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 689ce9dc2..e250c2d7e 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -369,10 +369,10 @@ Whenever :app:`Pyramid` returns a response from a view it creates a :class:`pyramid.response.Response` class is created to represent the response object. -The class (aka "factory") that :app:`Pyramid` uses to create a response object -instance can be changed by passing a ``response_factory`` argument to the -constructor of the :term:`configurator`. This argument can be either a -callable or a :term:`dotted Python name` representing a callable. +The factory that :app:`Pyramid` uses to create a response object instance can be +changed by passing a ``response_factory`` argument to the constructor of the +:term:`configurator`. This argument can be either a callable or a +:term:`dotted Python name` representing a callable. .. code-block:: python :linenos: @@ -382,7 +382,7 @@ callable or a :term:`dotted Python name` representing a callable. class MyResponse(Response): pass - config = Configurator(response_factory=MyResponse) + config = Configurator(response_factory=lambda r: MyResponse()) If you're doing imperative configuration, and you'd rather do it after you've already constructed a :term:`configurator` it can also be registered via the @@ -398,25 +398,8 @@ already constructed a :term:`configurator` it can also be registered via the pass config = Configurator() - config.set_response_factory(MyRequest) - -If you are already using a custom ```request_factory`` you can also set the -``ResponseClass`` on your :class:`pyramid.request.Request`: - -.. code-block:: python - :linenos: - - from pyramid.config import Configurator - from pyramid.response import Response - from pyramid.request import Request - - class MyResponse(Response): - pass - - class MyRequest(Request): - ResponseClass = MyResponse + config.set_response_factory(lambda r: MyResponse()) - config = Configurator() Using The Before Render Event ----------------------------- diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 3d5390840..51dbd318b 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -449,8 +449,8 @@ class RendererHelper(object): if response is None: # request is None or request is not a pyramid.response.Response registry = self.registry - response_factory = _get_response_factory(registry, request) - response = response_factory() + response_factory = _get_response_factory(registry) + response = response_factory(request) if result is not None: if isinstance(result, text_type): diff --git a/pyramid/request.py b/pyramid/request.py index b66b8926c..fc957fae2 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -216,8 +216,8 @@ class Request( right" attributes (e.g. by calling ``request.response.set_cookie()``) within a view that uses a renderer. Mutations to this response object will be preserved in the response sent to the client.""" - response_factory = _get_response_factory(self.registry, self) - return response_factory() + response_factory = _get_response_factory(self.registry) + return response_factory(self) def is_response(self, ob): """ Return ``True`` if the object passed as ``ob`` is a valid diff --git a/pyramid/testing.py b/pyramid/testing.py index f77889e72..66c694b31 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -9,7 +9,6 @@ from zope.interface import ( from pyramid.interfaces import ( IRequest, - IResponseFactory, ISession, ) @@ -40,7 +39,10 @@ from pyramid.threadlocal import ( from pyramid.i18n import LocalizerRequestMixin from pyramid.request import CallbackMethodsMixin from pyramid.url import URLMethodsMixin -from pyramid.util import InstancePropertyMixin +from pyramid.util import ( + InstancePropertyMixin, + _get_response_factory + ) _marker = object() @@ -383,8 +385,8 @@ class DummyRequest( @reify def response(self): - f = self.registry.queryUtility(IResponseFactory, default=Response) - return f() + f = _get_response_factory(self.registry) + return f(self) have_zca = True diff --git a/pyramid/tests/test_config/test_factories.py b/pyramid/tests/test_config/test_factories.py index c6785d4a5..0bd5336ff 100644 --- a/pyramid/tests/test_config/test_factories.py +++ b/pyramid/tests/test_config/test_factories.py @@ -26,7 +26,7 @@ class TestFactoriesMixin(unittest.TestCase): def test_set_response_factory(self): from pyramid.interfaces import IResponseFactory config = self._makeOne(autocommit=True) - factory = object() + factory = lambda r: object() config.set_response_factory(factory) self.assertEqual(config.registry.getUtility(IResponseFactory), factory) diff --git a/pyramid/tests/test_config/test_init.py b/pyramid/tests/test_config/test_init.py index 8fa6be011..aeebe3c91 100644 --- a/pyramid/tests/test_config/test_init.py +++ b/pyramid/tests/test_config/test_init.py @@ -551,43 +551,13 @@ class ConfiguratorTests(unittest.TestCase): from pyramid.interfaces import IResponseFactory reg = Registry() config = self._makeOne(reg) - factory = object() + factory = lambda r: object() config.setup_registry(response_factory=factory) self.assertEqual(reg.queryUtility(IResponseFactory), None) config.commit() utility = reg.getUtility(IResponseFactory) self.assertEqual(utility, factory) - def test_setup_registry_request_factory_custom_response_class(self): - from pyramid.registry import Registry - from pyramid.interfaces import IRequestFactory - from pyramid.request import Request - - class MyResponse(object): - pass - - class MyRequest(Request): - ResponseClass = MyResponse - - reg = Registry() - config = self._makeOne(reg) - factory = MyRequest({ - 'PATH_INFO': '/', - 'wsgi.url_scheme': 'http', - 'HTTP_HOST': 'localhost', - 'SERVER_PROTOCOL': '1.0', - }) - factory.registry = reg - - config.setup_registry(request_factory=factory) - self.assertEqual(reg.queryUtility(IRequestFactory), None) - config.commit() - utility = reg.getUtility(IRequestFactory) - self.assertEqual(utility, factory) - - new_response = factory.response - self.assertTrue(isinstance(new_response, MyResponse)) - def test_setup_registry_request_factory_dottedname(self): from pyramid.registry import Registry from pyramid.interfaces import IRequestFactory diff --git a/pyramid/tests/test_renderers.py b/pyramid/tests/test_renderers.py index 2bddd2318..21878b41f 100644 --- a/pyramid/tests/test_renderers.py +++ b/pyramid/tests/test_renderers.py @@ -182,7 +182,10 @@ class TestRendererHelper(unittest.TestCase): from pyramid.interfaces import IResponseFactory class ResponseFactory(object): pass - self.config.registry.registerUtility(ResponseFactory, IResponseFactory) + + self.config.registry.registerUtility( + lambda r: ResponseFactory(), IResponseFactory + ) def test_render_to_response(self): self._registerRendererFactory() @@ -310,7 +313,9 @@ class TestRendererHelper(unittest.TestCase): class ResponseFactory(object): def __init__(self): pass - self.config.registry.registerUtility(ResponseFactory, IResponseFactory) + self.config.registry.registerUtility( + lambda r: ResponseFactory(), IResponseFactory + ) request = testing.DummyRequest() helper = self._makeOne('loo.foo') response = helper._make_response(b'abc', request) diff --git a/pyramid/tests/test_testing.py b/pyramid/tests/test_testing.py index dfcad2a0c..113f7e5f4 100644 --- a/pyramid/tests/test_testing.py +++ b/pyramid/tests/test_testing.py @@ -259,7 +259,9 @@ class TestDummyRequest(unittest.TestCase): registry = Registry('this_test') class ResponseFactory(object): pass - registry.registerUtility(ResponseFactory, IResponseFactory) + registry.registerUtility( + lambda r: ResponseFactory(), IResponseFactory + ) request = self._makeOne() request.registry = registry resp = request.response diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index 0ebbd80a2..ba128eede 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -324,7 +324,7 @@ class Test_object_description(unittest.TestCase): self.assertEqual( self._callFUT(inst), "object %s" % str(inst)) - + def test_shortened_repr(self): inst = ['1'] * 1000 self.assertEqual( @@ -592,7 +592,7 @@ class TestActionInfo(unittest.TestCase): def _getTargetClass(self): from pyramid.util import ActionInfo return ActionInfo - + def _makeOne(self, filename, lineno, function, linerepr): return self._getTargetClass()(filename, lineno, function, linerepr) @@ -620,30 +620,14 @@ class TestActionInfo(unittest.TestCase): class TestGetResponseFactory(unittest.TestCase): - def test_no_request(self): + def test_get_factory(self): from pyramid.util import _get_response_factory from pyramid.registry import Registry from pyramid.response import Response registry = Registry() - factory = _get_response_factory(registry) - self.assertEqual(factory, Response) - - def test_with_request(self): - from pyramid.util import _get_response_factory - from pyramid.registry import Registry - from pyramid.request import Request - - class MyResponse(object): - pass - - class MyRequest(Request): - ResponseClass = MyResponse - registry = Registry() - - request = MyRequest({}) - factory = _get_response_factory(request.registry, request) - self.assertEqual(factory, MyResponse) + response = _get_response_factory(registry)(None) + self.assertTrue(isinstance(response, Response)) def dummyfunc(): pass diff --git a/pyramid/util.py b/pyramid/util.py index ee642164a..7aecca19c 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -556,19 +556,14 @@ def action_method(wrapped): wrapper.__docobj__ = wrapped return wrapper -def _get_response_factory(registry, request=None): + +def _get_response_factory(registry): """ Obtain a :class: `pyramid.response.Response` using the - ``request.ResponseClass`` property if available. + `pyramid.interfaces.IResponseFactory`. """ - # Request is `None` or does not have a `ResponseClass` - if hasattr(request, 'ResponseClass'): - response_class = request.ResponseClass - else: - response_class = Response - response_factory = registry.queryUtility( IResponseFactory, - default=response_class + default=lambda r: Response() ) return response_factory -- cgit v1.2.3 From ff01cdf0e392eb4e7926970a0cdee75663edb431 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 15:10:55 -0800 Subject: Fix typo --- docs/glossary.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/glossary.rst b/docs/glossary.rst index 38133f68f..911c22075 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -17,7 +17,7 @@ Glossary positional argument, returns a Pyramid-compatible request. response factory - An object which, provied a :term:`request` as a single positional + An object which, provided a :term:`request` as a single positional argument, returns a Pyramid-compatible response. response -- cgit v1.2.3 From a62462606704081b37ae0cb4c9f07a4690480609 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 15:26:00 -0800 Subject: Added CHANGES entry for this PR --- CHANGES.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index 46c331268..129ce4616 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -59,6 +59,11 @@ Features via ``request.static_url('myapp:static/foo.png')``. See https://github.com/Pylons/pyramid/issues/1252 +- Added ``pyramid.config.Configurator.set_response_factory`` and the + ``response_factory`` keyword argument to the ``Configurator`` for defining + a factory that will return a custom ``Response`` class. + See https://github.com/Pylons/pyramid/pull/1499 + Bug Fixes --------- -- cgit v1.2.3 From 303abc8b585d97c75773b3cfa48b6e748c96fd64 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 20:15:12 -0800 Subject: Move _get_response_factory to pyramid.response --- pyramid/renderers.py | 4 +--- pyramid/request.py | 7 ++----- pyramid/response.py | 17 +++++++++++++++-- pyramid/testing.py | 8 +++----- pyramid/tests/test_response.py | 17 +++++++++++++---- pyramid/tests/test_util.py | 11 ----------- pyramid/util.py | 12 ------------ 7 files changed, 34 insertions(+), 42 deletions(-) diff --git a/pyramid/renderers.py b/pyramid/renderers.py index 51dbd318b..d57671865 100644 --- a/pyramid/renderers.py +++ b/pyramid/renderers.py @@ -18,15 +18,13 @@ from pyramid.compat import ( text_type, ) -from pyramid.util import _get_response_factory - from pyramid.decorator import reify from pyramid.events import BeforeRender from pyramid.path import caller_package -from pyramid.response import Response +from pyramid.response import Response, _get_response_factory from pyramid.threadlocal import get_current_registry # API diff --git a/pyramid/request.py b/pyramid/request.py index fc957fae2..b2e2efe05 100644 --- a/pyramid/request.py +++ b/pyramid/request.py @@ -20,16 +20,13 @@ from pyramid.compat import ( from pyramid.decorator import reify from pyramid.i18n import LocalizerRequestMixin -from pyramid.response import Response +from pyramid.response import Response, _get_response_factory from pyramid.security import ( AuthenticationAPIMixin, AuthorizationAPIMixin, ) from pyramid.url import URLMethodsMixin -from pyramid.util import ( - InstancePropertyMixin, - _get_response_factory, -) +from pyramid.util import InstancePropertyMixin class TemplateContext(object): pass diff --git a/pyramid/response.py b/pyramid/response.py index d11fd0123..892e5dfff 100644 --- a/pyramid/response.py +++ b/pyramid/response.py @@ -8,7 +8,8 @@ import venusian from webob import Response as _Response from zope.interface import implementer -from pyramid.interfaces import IResponse +from pyramid.interfaces import IResponse, IResponseFactory + def init_mimetypes(mimetypes): # this is a function so it can be unittested @@ -143,7 +144,7 @@ class response_adapter(object): @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: @@ -167,3 +168,15 @@ class response_adapter(object): def __call__(self, wrapped): self.venusian.attach(wrapped, self.register, category='pyramid') return wrapped + + +def _get_response_factory(registry): + """ Obtain a :class: `pyramid.response.Response` using the + `pyramid.interfaces.IResponseFactory`. + """ + response_factory = registry.queryUtility( + IResponseFactory, + default=lambda r: Response() + ) + + return response_factory diff --git a/pyramid/testing.py b/pyramid/testing.py index 66c694b31..667e6af4e 100644 --- a/pyramid/testing.py +++ b/pyramid/testing.py @@ -21,7 +21,7 @@ from pyramid.compat import ( from pyramid.config import Configurator from pyramid.decorator import reify from pyramid.path import caller_package -from pyramid.response import Response +from pyramid.response import Response, _get_response_factory from pyramid.registry import Registry from pyramid.security import ( @@ -39,10 +39,8 @@ from pyramid.threadlocal import ( from pyramid.i18n import LocalizerRequestMixin from pyramid.request import CallbackMethodsMixin from pyramid.url import URLMethodsMixin -from pyramid.util import ( - InstancePropertyMixin, - _get_response_factory - ) +from pyramid.util import InstancePropertyMixin + _marker = object() diff --git a/pyramid/tests/test_response.py b/pyramid/tests/test_response.py index 84ec57757..ad55882c9 100644 --- a/pyramid/tests/test_response.py +++ b/pyramid/tests/test_response.py @@ -8,7 +8,7 @@ class TestResponse(unittest.TestCase): def _getTargetClass(self): from pyramid.response import Response return Response - + def test_implements_IResponse(self): from pyramid.interfaces import IResponse cls = self._getTargetClass() @@ -119,7 +119,7 @@ class Test_patch_mimetypes(unittest.TestCase): result = self._callFUT(module) self.assertEqual(result, True) self.assertEqual(module.initted, True) - + def test_missing_init(self): class DummyMimetypes(object): pass @@ -174,6 +174,17 @@ class TestResponseAdapter(unittest.TestCase): self.assertEqual(dummy_venusian.attached, [(foo, dec.register, 'pyramid')]) + +class TestGetResponseFactory(unittest.TestCase): + def test_get_factory(self): + from pyramid.registry import Registry + from pyramid.response import Response, _get_response_factory + + registry = Registry() + response = _get_response_factory(registry)(None) + self.assertTrue(isinstance(response, Response)) + + class Dummy(object): pass @@ -190,5 +201,3 @@ class DummyVenusian(object): def attach(self, wrapped, fn, category=None): self.attached.append((wrapped, fn, category)) - - diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py index ba128eede..ac5ea0683 100644 --- a/pyramid/tests/test_util.py +++ b/pyramid/tests/test_util.py @@ -619,17 +619,6 @@ class TestActionInfo(unittest.TestCase): "Line 0 of file filename:\n linerepr ") -class TestGetResponseFactory(unittest.TestCase): - def test_get_factory(self): - from pyramid.util import _get_response_factory - from pyramid.registry import Registry - from pyramid.response import Response - - registry = Registry() - response = _get_response_factory(registry)(None) - self.assertTrue(isinstance(response, Response)) - - def dummyfunc(): pass class Dummy(object): diff --git a/pyramid/util.py b/pyramid/util.py index 7aecca19c..4ca2937a1 100644 --- a/pyramid/util.py +++ b/pyramid/util.py @@ -555,15 +555,3 @@ def action_method(wrapped): functools.update_wrapper(wrapper, wrapped) wrapper.__docobj__ = wrapped return wrapper - - -def _get_response_factory(registry): - """ Obtain a :class: `pyramid.response.Response` using the - `pyramid.interfaces.IResponseFactory`. - """ - response_factory = registry.queryUtility( - IResponseFactory, - default=lambda r: Response() - ) - - return response_factory -- cgit v1.2.3