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 8c54a34d5d3211537b8705b04ae8662274641828 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Dec 2014 02:32:58 -0800 Subject: - adding back .png file because PDF cannot include and build SVG files. Also renamed images to use a 'imagename.*' wildcard so that the correct format is chosen. See http://stackoverflow.com/questions/6473660/using-sphinx-docs-how-can-i-specify-png-image-formats-for-html-builds-and-pdf-im --- docs/_static/pyramid_router.png | Bin 0 -> 120643 bytes docs/narr/router.rst | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 docs/_static/pyramid_router.png diff --git a/docs/_static/pyramid_router.png b/docs/_static/pyramid_router.png new file mode 100644 index 000000000..3c9f81158 Binary files /dev/null and b/docs/_static/pyramid_router.png differ diff --git a/docs/narr/router.rst b/docs/narr/router.rst index 693217a6b..6f90c70cc 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -9,7 +9,7 @@ Request Processing ================== -.. image:: ../_static/pyramid_request_processing.svg +.. image:: ../_static/pyramid_request_processing.* :alt: Request Processing Once a :app:`Pyramid` application is up and running, it is ready to accept @@ -119,7 +119,7 @@ request enters a :app:`Pyramid` application through to the point that #. The :term:`thread local` stack is popped. -.. image:: ../_static/pyramid_router.svg +.. image:: ../_static/pyramid_router.* :alt: Pyramid Router This is a very high-level overview that leaves out various details. For more -- cgit v1.2.3 From 432e61ed8e0174850ddfeefc81fb31c27a018fa7 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Dec 2014 02:49:01 -0800 Subject: - establish minimum version of 1.2.3 for Sphinx. I hope this works. See https://github.com/Pylons/pyramid/issues/1068 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d736dc38d..629b77f3d 100644 --- a/setup.py +++ b/setup.py @@ -56,7 +56,7 @@ if not PY3: tests_require.append('zope.component>=3.11.0') docs_extras = [ - 'Sphinx', + 'Sphinx >= 1.2.3', 'docutils', 'repoze.sphinx.autointerface', ] -- 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 cb5afac9c9539967591a46f50efdf6ee0d207fbf Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Dec 2014 19:59:43 -0800 Subject: - pin Sphinx >= 1.2.3 for RTD --- rtd.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtd.txt b/rtd.txt index b449ac73c..4aecd9933 100644 --- a/rtd.txt +++ b/rtd.txt @@ -1,4 +1,4 @@ +Sphinx >= 1.2.3 repoze.sphinx.autointerface repoze.lru pylons_sphinx_latesturl - -- cgit v1.2.3 From d579409e656df9f92a89000d66e60ec71b5857bc Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Fri, 26 Dec 2014 21:35:06 -0800 Subject: - update theme with new image --- docs/_themes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_themes b/docs/_themes index 3bec9280a..b14bf8c2a 160000 --- a/docs/_themes +++ b/docs/_themes @@ -1 +1 @@ -Subproject commit 3bec9280a6cedb15e97e5899021aa8d723c25388 +Subproject commit b14bf8c2a0d95ae8e3d38d07ad3721370ae6f3f8 -- 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 0882f7f0f4648b37617543a196ec4d5bf6d65278 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 17:42:57 -0800 Subject: Setup logging with prequest --- pyramid/scripts/prequest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyramid/scripts/prequest.py b/pyramid/scripts/prequest.py index 2ab3b8bb9..92faa146c 100644 --- a/pyramid/scripts/prequest.py +++ b/pyramid/scripts/prequest.py @@ -5,7 +5,7 @@ import textwrap from pyramid.compat import url_unquote from pyramid.request import Request -from pyramid.paster import get_app +from pyramid.paster import get_app, setup_logging from pyramid.scripts.common import parse_vars def main(argv=sys.argv, quiet=False): @@ -102,6 +102,7 @@ class PRequestCommand(object): self.out('You must provide at least two arguments') return 2 app_spec = self.args[0] + setup_logging(app_spec) path = self.args[1] if not path.startswith('/'): path = '/' + path -- cgit v1.2.3 From aa9aef58b5b2fe4c9135aadc5481d129f1300154 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 17:56:13 -0800 Subject: Added a test for configuring logging --- pyramid/scripts/prequest.py | 7 ++++++- pyramid/tests/test_scripts/test_prequest.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/pyramid/scripts/prequest.py b/pyramid/scripts/prequest.py index 92faa146c..34eeadf32 100644 --- a/pyramid/scripts/prequest.py +++ b/pyramid/scripts/prequest.py @@ -97,13 +97,18 @@ class PRequestCommand(object): if not self.quiet: print(msg) + def configure_logging(self, app_spec): + setup_logging(app_spec) + def run(self): if not len(self.args) >= 2: self.out('You must provide at least two arguments') return 2 app_spec = self.args[0] - setup_logging(app_spec) path = self.args[1] + + self.configure_logging(app_spec) + if not path.startswith('/'): path = '/' + path diff --git a/pyramid/tests/test_scripts/test_prequest.py b/pyramid/tests/test_scripts/test_prequest.py index 37f1d3c0f..95cec0518 100644 --- a/pyramid/tests/test_scripts/test_prequest.py +++ b/pyramid/tests/test_scripts/test_prequest.py @@ -210,8 +210,21 @@ class TestPRequestCommand(unittest.TestCase): self.assertEqual(self._path_info, '/') self.assertEqual(self._spec, 'development.ini') self.assertEqual(self._app_name, None) + self.assertEqual(self._out, [b'abc']) + def test_command_method_configures_logging(self): + command = self._makeOne(['', 'development.ini', '/']) + called_args = [] + + def configure_logging(app_spec): + called_args.append(app_spec) + + command.configure_logging = configure_logging + command.run() + self.assertEqual(called_args, ['development.ini']) + + class Test_main(unittest.TestCase): def _callFUT(self, argv): from pyramid.scripts.prequest import main -- 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