summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2011-01-02 19:26:42 -0500
committerChris McDonough <chrism@plope.com>2011-01-02 19:26:42 -0500
commitd95cd9b81d4e536c1e7f6f84457deb2fb34f1ea3 (patch)
tree15ef8c4694fe01a5af12af5459b343d6632f466c
parent405fcc2b4a5c6d3ab3d0680a216e48528e5aaf1a (diff)
downloadpyramid-d95cd9b81d4e536c1e7f6f84457deb2fb34f1ea3.tar.gz
pyramid-d95cd9b81d4e536c1e7f6f84457deb2fb34f1ea3.tar.bz2
pyramid-d95cd9b81d4e536c1e7f6f84457deb2fb34f1ea3.zip
- Allow static renderer provided during view registration to be overridden at
request time via a request attribute named ``override_renderer``, which should be the name of a registered renderer. Useful to provide "omnipresent" RPC for existing views. - Convert ``add_view_mapper`` to ``set_view_mapper``. There will only be a single default view mapper. We no longer register named utilities for view mappers to provide alternates. - Previoulsy the ``view_mapper`` argument was required to be the *name* of an existing registered view mapper. We no longer register named utilities for view mappers, so now if an extension wants to override the view mapper used for a particular view registration, it can use the dotted name to a view mapper class or provide that class as ``view_mapper``.
-rw-r--r--CHANGES.txt37
-rw-r--r--pyramid/config.py74
-rw-r--r--pyramid/tests/test_config.py27
3 files changed, 83 insertions, 55 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 4279f950d..ec631cc78 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -15,22 +15,6 @@ Features
- ``config.add_view`` now accepts a ``decorator`` keyword argument, a callable
which will decorate the view callable before it is added to the registry.
-- add a ``add_view_mapper`` API to Configurator. This API allows you to add
- a named implementation of a ``pyramid.interfaces.IViewMapperFactory``
- interface. Its name can be passed as a ``view_mapper`` argument to
- ``config.add_view``. A view mapper allows objects that are meant to be
- used as view callables to have an arbitrary argument list and an arbitrary
- result. This feature will be used by Pyramid extension developers, not by
- "civilians".
-
-- New constructor argument to Configurator: ``default_view_mapper``. Useful
- to create systems that have view callables with alternate default calling
- conventions.
-
-- ``config.add_view`` now accepts a ``view_mapper`` keyword argument, which
- should either be ``None`` or the name of a view mapper previously
- registered via ``add_view_mapper``.
-
- If a handler class provides an ``__action_decorator__`` attribute (usually
a classmethod or staticmethod), use that as the decorator for each view
registration for that handler.
@@ -55,6 +39,27 @@ Features
This class can be used by third-party authentication policy developers to
help in the mechanics of authentication cookie-setting.
+- New constructor argument to Configurator: ``default_view_mapper``. Useful
+ to create systems that have alternate view calling conventions. A view
+ mapper allows objects that are meant to be used as view callables to have
+ an arbitrary argument list and an arbitrary result. The object passed as
+ ``default_view_mapper`` should implement the
+ ``pyramid.interfaces.IViewMapperFactory`` interface.
+
+- add a ``set_view_mapper`` API to Configurator. Has
+ the same result as passing ``default_view_mapper`` to the Configurator
+ constructor.
+
+- ``config.add_view`` now accepts a ``view_mapper`` keyword argument, which
+ should either be ``None``, a string representing a Python dotted name, or
+ an object which is an ``IViewMapperFactory``. This feature is not useful
+ for "civilians", only for extension writers.
+
+- Allow static renderer provided during view registration to be overridden at
+ request time via a request attribute named ``override_renderer``, which
+ should be the name of a previously registered renderer. Useful to provide
+ "omnipresent" RPC using existing rendered views.
+
Backwards Incompatibilities
---------------------------
diff --git a/pyramid/config.py b/pyramid/config.py
index c890a0c59..5ecbfa064 100644
--- a/pyramid/config.py
+++ b/pyramid/config.py
@@ -656,7 +656,7 @@ class Configurator(object):
# mapper
self.commit()
if default_view_mapper is not None:
- self.add_view_mapper(None, default_view_mapper)
+ self.set_view_mapper(default_view_mapper)
self.commit()
# getSiteManager is a unit testing dep injection
@@ -1298,18 +1298,19 @@ class Configurator(object):
view_mapper
- The name of a previously registered :term:`view mapper` or
- ``None``. By default it is ``None``, which indicates that the view
- should use the default view mapper. This plug-point is useful for
- Pyramid extension developers, but it's not very useful for
- 'civilians' who are just developing stock Pyramid applications.
- Pay no attention to the man behind the curtain.
+ A Python object or :term:`dotted Python name` which refers to a
+ :term:`view mapper`, or ``None``. By default it is ``None``, which
+ indicates that the view should use the default view mapper. This
+ plug-point is useful for Pyramid extension developers, but it's not
+ very useful for 'civilians' who are just developing stock Pyramid
+ applications. Pay no attention to the man behind the curtain.
"""
view = self.maybe_dotted(view)
context = self.maybe_dotted(context)
for_ = self.maybe_dotted(for_)
containment = self.maybe_dotted(containment)
+ view_mapper = self.maybe_dotted(view_mapper)
if not view:
if renderer:
@@ -2175,34 +2176,27 @@ class Configurator(object):
self.action(IDefaultPermission, None)
@action_method
- def add_view_mapper(self, name, mapper):
+ def set_view_mapper(self, mapper):
"""
- Adding a :term:`view mapper` makes it possible to make use of
- :term:`view callable` objects which implement a different call
- signature than the ones described in the :app:`Pyramid`
- documentation. This is an advanced feature, not usually consumed by
- 'civilians'.
-
- ``name`` must be a string or ``None``. If ``name`` is a string, the
- view mapper will be registered under the specified name for
- consumption by extensions. If ``name`` is ``None``, the provided
- mapper will become the *default* view mapper to be used by all
- subsequent :term:`view configuration` registrations, as if you had
- passed a ``default_view_mapper`` argument to the
- :class:`pyramid.config.Configurator` constructor.
-
+ Setting a :term:`view mapper` makes it possible to make use of
+ :term:`view callable` objects which implement different call
+ signatures than the ones supported by :app:`Pyramid` as described in
+ its narrative documentation.
+
The ``mapper`` should argument be an object implementing
:class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted
Python name` to such an object.
+ The provided ``mapper`` will become the default view mapper to be
+ used by all subsequent :term:`view configuration` registrations, as
+ if you had passed a ``default_view_mapper`` argument to the
+ :class:`pyramid.config.Configurator` constructor.
+
See also :ref:`using_an_alternate_view_mapper`.
"""
- if mapper is not None:
- mapper = self.maybe_dotted(mapper)
- if name is None:
- name = ''
- self.registry.registerUtility(mapper, IViewMapperFactory, name=name)
- self.action((IViewMapperFactory, name), None)
+ mapper = self.maybe_dotted(mapper)
+ self.registry.registerUtility(mapper, IViewMapperFactory)
+ self.action(IViewMapperFactory, None)
@action_method
def set_session_factory(self, session_factory):
@@ -2791,12 +2785,11 @@ class ViewDeriver(object):
@wraps_view
def mapped_view(self, view):
- mapper_name = self.kw.get('view_mapper')
- mapper = self.registry.queryUtility(IViewMapperFactory,
- name=mapper_name)
-
+ mapper = self.kw.get('view_mapper')
if mapper is None:
- mapper = DefaultViewMapper
+ mapper = self.registry.queryUtility(IViewMapperFactory)
+ if mapper is None:
+ mapper = DefaultViewMapper
mapped_view = mapper(**self.kw)(view)
return mapped_view
@@ -2919,14 +2912,25 @@ class ViewDeriver(object):
@wraps_view
def rendered_view(self, view):
wrapped_view = view
- renderer = self.kw.get('renderer')
- if renderer is None:
+ static_renderer = self.kw.get('renderer')
+ if static_renderer is None:
+ # register a default renderer if you want super-dynamic
+ # rendering. registering a default renderer will also allow
+ # override_renderer to work if a renderer is left unspecified for
+ # a view registration.
return view
def _rendered_view(context, request):
+ renderer = static_renderer
response = wrapped_view(context, request)
if not is_response(response):
attrs = getattr(request, '__dict__', {})
+ if 'override_renderer' in attrs:
+ # renderer overridden by newrequest event or other
+ renderer_name = attrs.pop('override_renderer')
+ renderer = RendererHelper(name=renderer_name,
+ package=self.kw.get('package'),
+ registry = self.kw['registry'])
if '__view__' in attrs:
view_inst = attrs.pop('__view__')
else:
diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py
index ceb62612f..52760d6d7 100644
--- a/pyramid/tests/test_config.py
+++ b/pyramid/tests/test_config.py
@@ -2678,15 +2678,15 @@ class ConfiguratorTests(unittest.TestCase):
from pyramid.interfaces import IViewMapperFactory
config = self._makeOne(autocommit=True)
mapper = object()
- config.add_view_mapper('mapper', mapper)
- result = config.registry.getUtility(IViewMapperFactory, name='mapper')
+ config.set_view_mapper(mapper)
+ result = config.registry.getUtility(IViewMapperFactory)
self.assertEqual(result, mapper)
def test_add_view_mapper_dottedname(self):
from pyramid.interfaces import IViewMapperFactory
config = self._makeOne(autocommit=True)
- config.add_view_mapper('mapper', 'pyramid.tests.test_config')
- result = config.registry.getUtility(IViewMapperFactory, name='mapper')
+ config.set_view_mapper('pyramid.tests.test_config')
+ result = config.registry.getUtility(IViewMapperFactory)
from pyramid.tests import test_config
self.assertEqual(result, test_config)
@@ -3271,6 +3271,25 @@ class TestViewDeriver(unittest.TestCase):
context = testing.DummyResource()
self.assertEqual(result(context, request), 'moo')
+ def test_requestonly_function_with_renderer_request_override(self):
+ def moo(info):
+ def inner(value, system):
+ self.assertEqual(value, 'OK')
+ self.assertEqual(system['request'], request)
+ self.assertEqual(system['context'], context)
+ return 'moo'
+ return inner
+ def view(request):
+ return 'OK'
+ self.config.add_renderer('moo', moo)
+ deriver = self._makeOne(renderer='string')
+ result = deriver(view)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ request.override_renderer = 'moo'
+ context = testing.DummyResource()
+ self.assertEqual(result(context, request).body, 'moo')
+
def test_requestonly_function_with_renderer_request_has_view(self):
class moo(object):
def render_view(inself, req, resp, view_inst, ctx):