diff options
| author | Chris McDonough <chrism@plope.com> | 2011-01-02 19:26:42 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-01-02 19:26:42 -0500 |
| commit | d95cd9b81d4e536c1e7f6f84457deb2fb34f1ea3 (patch) | |
| tree | 15ef8c4694fe01a5af12af5459b343d6632f466c | |
| parent | 405fcc2b4a5c6d3ab3d0680a216e48528e5aaf1a (diff) | |
| download | pyramid-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.txt | 37 | ||||
| -rw-r--r-- | pyramid/config.py | 74 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 27 |
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): |
