diff options
| author | Chris McDonough <chrism@plope.com> | 2011-01-02 04:08:18 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-01-02 04:08:18 -0500 |
| commit | 80aa770ad2230f01611eb6f49080321faf77d9fe (patch) | |
| tree | a5717c9444a996c25f8e0b925f3dac8468cce7e5 | |
| parent | 60eccf86ed9073644e525a84f2bed5390651e3a4 (diff) | |
| download | pyramid-80aa770ad2230f01611eb6f49080321faf77d9fe.tar.gz pyramid-80aa770ad2230f01611eb6f49080321faf77d9fe.tar.bz2 pyramid-80aa770ad2230f01611eb6f49080321faf77d9fe.zip | |
- 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.
- ``view_mapper`` argument to ``add_view`` should now be a view mapper *name*
rather than an implementation.
- Add ``view_mapper`` argument to ``view_config`` decorator constructor.
- Remove (non-API) function of config.py named _map_view.
- Fix docstring for ``decorator`` argument to add_view.
- Factor invocation of view mapper into a viewderiver method.
- Promote view rendering and decorating into viewderiver, out of view mapper.
- Make requestonly into a function rather than a method of the default view
mapper.
| -rw-r--r-- | CHANGES.txt | 20 | ||||
| -rw-r--r-- | TODO.txt | 4 | ||||
| -rw-r--r-- | docs/glossary.rst | 7 | ||||
| -rw-r--r-- | pyramid/config.py | 306 | ||||
| -rw-r--r-- | pyramid/tests/test_config.py | 1337 | ||||
| -rw-r--r-- | pyramid/tests/test_view.py | 3 | ||||
| -rw-r--r-- | pyramid/view.py | 4 |
7 files changed, 918 insertions, 763 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 6fe68fb48..4279f950d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -15,12 +15,21 @@ 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 be a class which implements the new - ``pyramid.interfaces.IViewMapperFactory`` interface. Use of an alternate - 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". + 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 @@ -90,6 +99,7 @@ Internals promoted to an API method. If you were overriding this method, you'll now need to override it as ``unauthenticated_userid`` instead. +- Remove (non-API) function of config.py named _map_view. 1.0a8 (2010-12-27) ================== @@ -16,6 +16,10 @@ Must-Have (before 1.0) - Allow ``decorator=`` and ``view_mapper=`` to be passed via ZCML and the ``view_config`` decorator. +- Document ``Configurator.add_view_mapper``. + +- Consider the ability to defer the choice of view mapper. + Should-Have ----------- diff --git a/docs/glossary.rst b/docs/glossary.rst index 49d273197..4d0c53d60 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -850,6 +850,11 @@ Glossary WSGI middleware which can display debuggable traceback information in the browser when an exception is raised by a Pyramid application. See http://pypi.python.org/pypi/WebError . - + view mapper + + A view mapper is a class which implements the + :class:`pyramid.interfaces.IViewMapperFactory` interface, which performs + view argument and return value mapping. This is a plug point for + extension builders, not normally used by "civilians". diff --git a/pyramid/config.py b/pyramid/config.py index 01d453cd1..c890a0c59 100644 --- a/pyramid/config.py +++ b/pyramid/config.py @@ -246,7 +246,13 @@ class Configurator(object): ``autocommit`` is ``True``. If a conflict is detected a ``ConfigurationConflictError`` will be raised. Calling :meth:`pyramid.config.Configurator.make_wsgi_app` always implies a final - commit.""" + commit. + + If ``default_view_mapper`` is passed, it will be used as the default + view mapper factory for view configurations that don't otherwise specify + one (see :class:`pyramid.interfaces.IViewMapperFactory`). + If a default_view_mapper is not passed, a superdefault view mapper will + be used. """ manager = manager # for testing injection venusian = venusian # for testing injection @@ -267,6 +273,7 @@ class Configurator(object): renderer_globals_factory=None, default_permission=None, session_factory=None, + default_view_mapper=None, autocommit=False, ): if package is None: @@ -292,6 +299,7 @@ class Configurator(object): renderer_globals_factory=renderer_globals_factory, default_permission=default_permission, session_factory=session_factory, + default_view_mapper=default_view_mapper, ) def _set_settings(self, mapping): @@ -596,9 +604,8 @@ class Configurator(object): authentication_policy=None, authorization_policy=None, renderers=DEFAULT_RENDERERS, debug_logger=None, locale_negotiator=None, request_factory=None, - renderer_globals_factory=None, - default_permission=None, - session_factory=None): + renderer_globals_factory=None, default_permission=None, + session_factory=None, default_view_mapper=None): """ When you pass a non-``None`` ``registry`` argument to the :term:`Configurator` constructor, no initial 'setup' is performed against the registry. This is because the registry you pass in may @@ -644,7 +651,13 @@ class Configurator(object): self.set_default_permission(default_permission) if session_factory is not None: self.set_session_factory(session_factory) + # commit before adding default_view_mapper, as the + # default_exceptionresponse_view above requires the superdefault view + # mapper self.commit() + if default_view_mapper is not None: + self.add_view_mapper(None, default_view_mapper) + self.commit() # getSiteManager is a unit testing dep injection def hook_zca(self, getSiteManager=None): @@ -1140,11 +1153,11 @@ class Configurator(object): decorator A function which will be used to decorate the registered - :term:`view callable`. The decorator function will be - called with the view callable as a single argument, and it - must return a replacement view callable which accepts the - same arguments and returns the same type of values as the - original function. + :term:`view callable`. The decorator function will be called with + the view callable as a single argument. The view callable it is + passed will accept ``(context, request)`. The decorator must + return a replacement view callable which also accepts ``(context, + request)``. Predicate Arguments @@ -1285,14 +1298,12 @@ class Configurator(object): view_mapper - A class implementing the - :class:`pyramid.interfaces.IViewMapperFactory` interface, which - performs view argument and response mapping. 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. + 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. """ view = self.maybe_dotted(view) @@ -1369,19 +1380,20 @@ class Configurator(object): # intent: will be None if no default permission is registered permission = self.registry.queryUtility(IDefaultPermission) - # NO_PERMISSION_REQUIRED handled by _secure_view - derived_view = ViewDeriver(registry=self.registry, - permission=permission, - predicates=predicates, - attr=attr, - renderer=renderer, - wrapper_viewname=wrapper, - viewname=name, - accept=accept, - order=order, - phash=phash, - decorator=decorator, - view_mapper=view_mapper)(view) + # __no_permission_required__ handled by _secure_view + deriver = ViewDeriver(registry=self.registry, + permission=permission, + predicates=predicates, + attr=attr, + renderer=renderer, + wrapper_viewname=wrapper, + viewname=name, + accept=accept, + order=order, + phash=phash, + decorator=decorator, + view_mapper=view_mapper) + derived_view = deriver(view) registered = self.registry.adapters.registered @@ -2163,6 +2175,36 @@ class Configurator(object): self.action(IDefaultPermission, None) @action_method + def add_view_mapper(self, name, 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. + + The ``mapper`` should argument be an object implementing + :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted + Python name` to such an object. + + 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) + + @action_method def set_session_factory(self, session_factory): """ Configure the application with a :term:`session factory`. If @@ -2738,19 +2780,29 @@ class ViewDeriver(object): self.logger = self.registry.queryUtility(IDebugLogger) def __call__(self, view): - mapper = self.kw.get('view_mapper') - if mapper is None: - mapper = DefaultViewMapper - view = mapper(**self.kw)(view) return self.attr_wrapped_view( self.predicated_view( self.authdebug_view( self.secured_view( - self.owrap_view( - view))))) + self.owrapped_view( + self.decorated_view( + self.rendered_view( + self.mapped_view(view)))))))) @wraps_view - def owrap_view(self, view): + def mapped_view(self, view): + mapper_name = self.kw.get('view_mapper') + mapper = self.registry.queryUtility(IViewMapperFactory, + name=mapper_name) + + if mapper is None: + mapper = DefaultViewMapper + + mapped_view = mapper(**self.kw)(view) + return mapped_view + + @wraps_view + def owrapped_view(self, view): wrapper_viewname = self.kw.get('wrapper_viewname') viewname = self.kw.get('viewname') if not wrapper_viewname: @@ -2864,29 +2916,53 @@ class ViewDeriver(object): attr_view.__phash__ = phash return attr_view + @wraps_view + def rendered_view(self, view): + wrapped_view = view + renderer = self.kw.get('renderer') + if renderer is None: + return view + + def _rendered_view(context, request): + response = wrapped_view(context, request) + if not is_response(response): + attrs = getattr(request, '__dict__', {}) + if '__view__' in attrs: + view_inst = attrs.pop('__view__') + else: + view_inst = getattr(wrapped_view, '__original_view__', + wrapped_view) + return renderer.render_view(request, response, view_inst, + context) + return response + + return _rendered_view + + @wraps_view + def decorated_view(self, view): + decorator = self.kw.get('decorator') + if decorator is None: + return view + return decorator(view) + class DefaultViewMapper(object): implements(IViewMapperFactory) def __init__(self, **kw): - self.renderer = kw.get('renderer') self.attr = kw.get('attr') - self.decorator = kw.get('decorator') def __call__(self, view): - decorator = self.decorator if inspect.isclass(view): - view = preserve_view_attrs(view, self.map_class(view)) + view = self.map_class(view) else: - view = preserve_view_attrs(view, self.map_nonclass(view)) - if decorator is not None: - view = preserve_view_attrs(view, decorator(view)) + view = self.map_nonclass(view) return view def map_class(self, view): - ronly = self.requestonly(view) + ronly = requestonly(view, self.attr) if ronly: - mapped_view = self._map_class_requestonly(view) + mapped_view = self.map_class_requestonly(view) else: - mapped_view = self._map_class_native(view) + mapped_view = self.map_class_native(view) return mapped_view def map_nonclass(self, view): @@ -2894,47 +2970,41 @@ class DefaultViewMapper(object): # view unless it actually requires wrapping (to avoid function call # overhead). mapped_view = view - ronly = self.requestonly(view) + ronly = requestonly(view, self.attr) if ronly: - mapped_view = self._map_nonclass_requestonly(view) + mapped_view = self.map_nonclass_requestonly(view) elif self.attr: - mapped_view = self._map_nonclass_attr(view) - elif self.renderer is not None: - mapped_view = self._map_nonclass_rendered(view) + mapped_view = self.map_nonclass_attr(view) return mapped_view - def _map_class_requestonly(self, view): + def map_class_requestonly(self, view): # its a class that has an __init__ which only accepts request attr = self.attr def _class_requestonly_view(context, request): inst = view(request) + request.__view__ = inst if attr is None: response = inst() else: response = getattr(inst, attr)() - if self.renderer is not None and not is_response(response): - response = self.renderer.render_view(request, response, view, - context) return response return _class_requestonly_view - def _map_class_native(self, view): + def map_class_native(self, view): # its a class that has an __init__ which accepts both context and # request attr = self.attr def _class_view(context, request): inst = view(context, request) + request.__view__ = inst if attr is None: response = inst() else: response = getattr(inst, attr)() - if self.renderer is not None and not is_response(response): - response = self.renderer.render_view(request, response, view, - context) return response return _class_view - def _map_nonclass_requestonly(self, view): + def map_nonclass_requestonly(self, view): # its a function that has a __call__ which accepts only a single # request argument attr = self.attr @@ -2943,86 +3013,58 @@ class DefaultViewMapper(object): response = view(request) else: response = getattr(view, attr)(request) - if self.renderer is not None and not is_response(response): - response = self.renderer.render_view(request, response, view, - context) return response return _requestonly_view - def _map_nonclass_attr(self, view): + def map_nonclass_attr(self, view): # its a function that has a __call__ which accepts both context and # request, but still has an attr - attr = self.attr def _attr_view(context, request): - response = getattr(view, attr)(context, request) - if self.renderer is not None and not is_response(response): - response = self.renderer.render_view(request, response, view, - context) + response = getattr(view, self.attr)(context, request) return response return _attr_view - def _map_nonclass_rendered(self, view): - # it's a function that has a __call__ that accepts both context and - # request, but requires rendering - def _rendered_view(context, request): - response = view(context, request) - if self.renderer is not None and not is_response(response): - response = self.renderer.render_view(request, response, view, - context) - return response - return _rendered_view - - def requestonly(self, view): - attr = self.attr - if attr is None: - attr = '__call__' - if inspect.isfunction(view): - fn = view - elif inspect.isclass(view): - try: - fn = view.__init__ - except AttributeError: - return False - else: - try: - fn = getattr(view, attr) - except AttributeError: - return False - +def requestonly(view, attr=None): + if attr is None: + attr = '__call__' + if inspect.isfunction(view): + fn = view + elif inspect.isclass(view): try: - argspec = inspect.getargspec(fn) - except TypeError: + fn = view.__init__ + except AttributeError: return False - - args = argspec[0] - defaults = argspec[3] - - if hasattr(fn, 'im_func'): - # it's an instance method - if not args: - return False - args = args[1:] - if not args: + else: + try: + fn = getattr(view, attr) + except AttributeError: return False - if len(args) == 1: - return True + try: + argspec = inspect.getargspec(fn) + except TypeError: + return False - elif args[0] == 'request': - if len(args) - len(defaults) == 1: - return True + args = argspec[0] + defaults = argspec[3] + if hasattr(fn, 'im_func'): + # it's an instance method + if not args: + return False + args = args[1:] + if not args: return False + if len(args) == 1: + return True -def isexception(o): - if IInterface.providedBy(o): - if IException.isEqualOrExtendedBy(o): + elif args[0] == 'request': + if len(args) - len(defaults) == 1: return True - return ( - isinstance(o, Exception) or - (inspect.isclass(o) and (issubclass(o, Exception))) - ) + + return False + class ActionPredicate(object): action_name = 'action' @@ -3069,20 +3111,18 @@ def translator(msg): localizer = get_localizer(request) return localizer.translate(msg) -# b/c -def _map_view(view, registry, attr=None, renderer=None): - return DefaultViewMapper(registry=registry, attr=attr, - renderer=renderer)(view) - -# b/c -def requestonly(view, attr=None): - """ Return true of the class or callable accepts only a request argument, - as opposed to something that accepts context, request """ - return DefaultViewMapper(attr=attr).requestonly(view) - def is_response(ob): if ( hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and hasattr(ob, 'status') ): return True return False +def isexception(o): + if IInterface.providedBy(o): + if IException.isEqualOrExtendedBy(o): + return True + return ( + isinstance(o, Exception) or + (inspect.isclass(o) and (issubclass(o, Exception))) + ) + diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py index 1760d119a..ceb62612f 100644 --- a/pyramid/tests/test_config.py +++ b/pyramid/tests/test_config.py @@ -63,27 +63,11 @@ class ConfiguratorTests(unittest.TestCase): config.registry.registerHandler(subscriber, (event_iface,)) return L - def _registerLogger(self, config): - from pyramid.interfaces import IDebugLogger - logger = DummyLogger() - config.registry.registerUtility(logger, IDebugLogger) - return logger - def _makeRequest(self, config): request = DummyRequest() request.registry = config.registry return request - def _registerSecurityPolicy(self, config, permissive): - from pyramid.interfaces import IAuthenticationPolicy - from pyramid.interfaces import IAuthorizationPolicy - policy = DummySecurityPolicy(permissive) - config.registry.registerUtility(policy, IAuthenticationPolicy) - config.registry.registerUtility(policy, IAuthorizationPolicy) - - def _registerSettings(self, config, **settings): - config.registry.settings = settings - def test_ctor_no_registry(self): import sys from pyramid.interfaces import ISettings @@ -196,6 +180,13 @@ class ConfiguratorTests(unittest.TestCase): config = self._makeOne(session_factory='factory') self.assertEqual(config.registry.getUtility(ISessionFactory), 'factory') + def test_ctor_default_view_mapper(self): + from pyramid.interfaces import IViewMapperFactory + mapper = object() + config = self._makeOne(default_view_mapper=mapper) + self.assertEqual(config.registry.getUtility(IViewMapperFactory), + mapper) + def test_with_package_module(self): from pyramid.tests import test_configuration import pyramid.tests @@ -790,8 +781,10 @@ class ConfiguratorTests(unittest.TestCase): config = self._makeOne(autocommit=True) config.add_view(view=view) wrapper = self._getViewCallable(config) - result = wrapper(None, None) + request = self._makeRequest(config) + result = wrapper(None, request) self.assertEqual(result, 'OK') + self.assertEqual(request.__view__.__class__, view) def test_add_view_as_oldstyle_class_requestonly(self): class view: @@ -803,8 +796,11 @@ class ConfiguratorTests(unittest.TestCase): config = self._makeOne(autocommit=True) config.add_view(view=view) wrapper = self._getViewCallable(config) - result = wrapper(None, None) + + request = self._makeRequest(config) + result = wrapper(None, request) self.assertEqual(result, 'OK') + self.assertEqual(request.__view__.__class__, view) def test_add_view_context_as_class(self): from zope.interface import implementedBy @@ -1427,8 +1423,6 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(result.settings, settings) def test_add_view_with_default_renderer(self): - import pyramid.tests - from pyramid.interfaces import ISettings class view(object): def __init__(self, context, request): self.request = request @@ -2340,7 +2334,8 @@ class ConfiguratorTests(unittest.TestCase): request_type = self._getRouteRequestIface(config, 'name') wrapper = self._getViewCallable(config, None, request_type) self._assertRoute(config, 'name', 'path') - self.assertEqual(wrapper(None, None), 'OK') + request = self._makeRequest(config) + self.assertEqual(wrapper(None, request), 'OK') def test_add_route_with_view_renderer_alias(self): config = self._makeOne(autocommit=True) @@ -2437,6 +2432,52 @@ class ConfiguratorTests(unittest.TestCase): else: # pragma: no cover raise AssertionError + def test_derive_view_function(self): + def view(request): + return 'OK' + config = self._makeOne() + result = config.derive_view(view) + self.failIf(result is view) + self.assertEqual(result(None, None), 'OK') + + def test_derive_view_dottedname(self): + config = self._makeOne() + result = config.derive_view( + 'pyramid.tests.test_config.dummy_view') + self.failIf(result is dummy_view) + self.assertEqual(result(None, None), 'OK') + + def test_derive_view_with_default_renderer_no_explicit_renderer(self): + config = self._makeOne() + class moo(object): + def __init__(self, view): + pass + def __call__(self, *arg, **kw): + return 'moo' + config.add_renderer(None, moo) + def view(request): + return 'OK' + result = config.derive_view(view) + self.failIf(result is view) + self.assertEqual(result(None, None).body, 'moo') + + def test_derive_view_with_default_renderer_with_explicit_renderer(self): + class moo(object): pass + class foo(object): + def __init__(self, view): + pass + def __call__(self, *arg, **kw): + return 'foo' + def view(request): + return 'OK' + config = self._makeOne() + config.add_renderer(None, moo) + config.add_renderer('foo', foo) + result = config.derive_view(view, renderer='foo') + self.failIf(result is view) + request = self._makeRequest(config) + self.assertEqual(result(None, request).body, 'foo') + def test__override_not_yet_registered(self): from pyramid.interfaces import IPackageOverrides package = DummyPackage('package') @@ -2633,6 +2674,22 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(config.registry.getUtility(IDefaultPermission), 'view') + def test_add_view_mapper(self): + 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') + 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') + from pyramid.tests import test_config + self.assertEqual(result, test_config) + def test_set_session_factory(self): from pyramid.interfaces import ISessionFactory config = self._makeOne(autocommit=True) @@ -2680,404 +2737,6 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(config.registry.getUtility(ITranslationDirectories), [locale]) - def test_derive_view_function(self): - def view(request): - return 'OK' - config = self._makeOne() - result = config.derive_view(view) - self.failIf(result is view) - self.assertEqual(result(None, None), 'OK') - - def test_derive_view_dottedname(self): - config = self._makeOne() - result = config.derive_view( - 'pyramid.tests.test_config.dummy_view') - self.failIf(result is dummy_view) - self.assertEqual(result(None, None), 'OK') - - def test_derive_view_with_renderer(self): - def view(request): - return 'OK' - config = self._makeOne(autocommit=True) - class moo(object): - def __init__(self, *arg, **kw): - pass - def __call__(self, *arg, **kw): - return 'moo' - config.add_renderer('moo', moo) - result = config.derive_view(view, renderer='moo') - self.failIf(result is view) - self.assertEqual(result(None, None).body, 'moo') - - def test_derive_view_with_default_renderer_no_explicit_renderer(self): - def view(request): - return 'OK' - config = self._makeOne(autocommit=True) - class moo(object): - def __init__(self, *arg, **kw): - pass - def __call__(self, *arg, **kw): - return 'moo' - config.add_renderer(None, moo) - result = config.derive_view(view) - self.failIf(result is view) - self.assertEqual(result(None, None).body, 'moo') - - def test_derive_view_with_default_renderer_with_explicit_renderer(self): - def view(request): - return 'OK' - config = self._makeOne(autocommit=True) - class moo(object): pass - class foo(object): - def __init__(self, *arg, **kw): - pass - def __call__(self, *arg, **kw): - return 'foo' - config.add_renderer(None, moo) - config.add_renderer('foo', foo) - result = config.derive_view(view, renderer='foo') - self.failIf(result is view) - self.assertEqual(result(None, None).body, 'foo') - - def test_derive_view_class_without_attr(self): - class View(object): - def __init__(self, request): - pass - def __call__(self): - return 'OK' - config = self._makeOne() - result = config.derive_view(View) - self.assertEqual(result(None, None), 'OK') - - def test_derive_view_class_with_attr(self): - class View(object): - def __init__(self, request): - pass - def another(self): - return 'OK' - config = self._makeOne() - result = config.derive_view(View, attr='another') - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_function_context_and_request(self): - def view(context, request): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failUnless(result is view) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(view(None, None), 'OK') - - def test__derive_view_as_function_requestonly(self): - def view(request): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_newstyle_class_context_and_request(self): - class view(object): - def __init__(self, context, request): - pass - def __call__(self): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_newstyle_class_requestonly(self): - class view(object): - def __init__(self, context, request): - pass - def __call__(self): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_oldstyle_class_context_and_request(self): - class view: - def __init__(self, context, request): - pass - def __call__(self): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_oldstyle_class_requestonly(self): - class view: - def __init__(self, context, request): - pass - def __call__(self): - return 'OK' - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_instance_context_and_request(self): - class View: - def __call__(self, context, request): - return 'OK' - view = View() - config = self._makeOne() - result = config._derive_view(view) - self.failUnless(result is view) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_as_instance_requestonly(self): - class View: - def __call__(self, request): - return 'OK' - view = View() - config = self._makeOne() - result = config._derive_view(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.failUnless('instance' in result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - self.assertEqual(result(None, None), 'OK') - - def test__derive_view_with_debug_authorization_no_authpol(self): - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, - debug_authorization=True, reload_templates=True) - logger = self._registerLogger(config) - result = config._derive_view(view, permission='view') - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - self.assertEqual(result(None, request), 'OK') - self.assertEqual(len(logger.messages), 1) - self.assertEqual(logger.messages[0], - "debug_authorization of url url (view name " - "'view_name' against context None): Allowed " - "(no authorization policy in use)") - - def test__derive_view_with_debug_authorization_no_permission(self): - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, - debug_authorization=True, reload_templates=True) - self._registerSecurityPolicy(config, True) - logger = self._registerLogger(config) - result = config._derive_view(view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - self.assertEqual(result(None, request), 'OK') - self.assertEqual(len(logger.messages), 1) - self.assertEqual(logger.messages[0], - "debug_authorization of url url (view name " - "'view_name' against context None): Allowed (" - "no permission registered)") - - def test__derive_view_debug_auth_permission_authpol_permitted(self): - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, debug_authorization=True, - reload_templates=True) - logger = self._registerLogger(config) - self._registerSecurityPolicy(config, True) - result = config._derive_view(view, permission='view') - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result.__call_permissive__, view) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - self.assertEqual(result(None, request), 'OK') - self.assertEqual(len(logger.messages), 1) - self.assertEqual(logger.messages[0], - "debug_authorization of url url (view name " - "'view_name' against context None): True") - - def test__derive_view_debug_auth_permission_authpol_denied(self): - from pyramid.exceptions import Forbidden - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, - debug_authorization=True, reload_templates=True) - logger = self._registerLogger(config) - self._registerSecurityPolicy(config, False) - result = config._derive_view(view, permission='view') - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result.__call_permissive__, view) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - self.assertRaises(Forbidden, result, None, request) - self.assertEqual(len(logger.messages), 1) - self.assertEqual(logger.messages[0], - "debug_authorization of url url (view name " - "'view_name' against context None): False") - - def test__derive_view_debug_auth_permission_authpol_denied2(self): - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, - debug_authorization=True, reload_templates=True) - self._registerLogger(config) - self._registerSecurityPolicy(config, False) - result = config._derive_view(view, permission='view') - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - permitted = result.__permitted__(None, None) - self.assertEqual(permitted, False) - - def test__derive_view_debug_auth_permission_authpol_overridden(self): - view = lambda *arg: 'OK' - config = self._makeOne() - self._registerSettings(config, - debug_authorization=True, reload_templates=True) - logger = self._registerLogger(config) - self._registerSecurityPolicy(config, False) - result = config._derive_view(view, - permission='__no_permission_required__') - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.failIf(hasattr(result, '__call_permissive__')) - request = self._makeRequest(config) - request.view_name = 'view_name' - request.url = 'url' - self.assertEqual(result(None, request), 'OK') - self.assertEqual(len(logger.messages), 1) - self.assertEqual(logger.messages[0], - "debug_authorization of url url (view name " - "'view_name' against context None): False") - - def test__derive_view_with_predicates_all(self): - view = lambda *arg: 'OK' - predicates = [] - def predicate1(context, request): - predicates.append(True) - return True - def predicate2(context, request): - predicates.append(True) - return True - config = self._makeOne() - result = config._derive_view(view, predicates=[predicate1, predicate2]) - request = self._makeRequest(config) - request.method = 'POST' - next = result(None, None) - self.assertEqual(next, 'OK') - self.assertEqual(predicates, [True, True]) - - def test__derive_view_with_predicates_checker(self): - view = lambda *arg: 'OK' - predicates = [] - def predicate1(context, request): - predicates.append(True) - return True - def predicate2(context, request): - predicates.append(True) - return True - config = self._makeOne() - result = config._derive_view(view, predicates=[predicate1, predicate2]) - request = self._makeRequest(config) - request.method = 'POST' - next = result.__predicated__(None, None) - self.assertEqual(next, True) - self.assertEqual(predicates, [True, True]) - - def test__derive_view_with_predicates_notall(self): - from pyramid.exceptions import NotFound - view = lambda *arg: 'OK' - predicates = [] - def predicate1(context, request): - predicates.append(True) - return True - def predicate2(context, request): - predicates.append(True) - return False - config = self._makeOne() - result = config._derive_view(view, predicates=[predicate1, predicate2]) - request = self._makeRequest(config) - request.method = 'POST' - self.assertRaises(NotFound, result, None, None) - self.assertEqual(predicates, [True, True]) - - def test__derive_view_with_wrapper_viewname(self): - from webob import Response - from pyramid.interfaces import IView - from pyramid.interfaces import IViewClassifier - inner_response = Response('OK') - def inner_view(context, request): - return inner_response - def outer_view(context, request): - self.assertEqual(request.wrapped_response, inner_response) - self.assertEqual(request.wrapped_body, inner_response.body) - self.assertEqual(request.wrapped_view, inner_view) - return Response('outer ' + request.wrapped_body) - config = self._makeOne() - config.registry.registerAdapter( - outer_view, (IViewClassifier, None, None), IView, 'owrap') - result = config._derive_view(inner_view, viewname='inner', - wrapper_viewname='owrap') - self.failIf(result is inner_view) - self.assertEqual(inner_view.__module__, result.__module__) - self.assertEqual(inner_view.__doc__, result.__doc__) - request = self._makeRequest(config) - request.registry = config.registry - response = result(None, request) - self.assertEqual(response.body, 'outer OK') - - def test__derive_view_with_wrapper_viewname_notfound(self): - from webob import Response - inner_response = Response('OK') - def inner_view(context, request): - return inner_response - config = self._makeOne() - request = self._makeRequest(config) - request.registry = config.registry - wrapped = config._derive_view( - inner_view, viewname='inner', wrapper_viewname='owrap') - self.assertRaises(ValueError, wrapped, None, request) - def test_override_asset_samename(self): from pyramid.exceptions import ConfigurationError config = self._makeOne() @@ -3557,334 +3216,755 @@ class ConfiguratorTests(unittest.TestCase): for confinst in conflict: yield confinst[2] -class Test__map_view(unittest.TestCase): +class TestViewDeriver(unittest.TestCase): def setUp(self): - from pyramid.registry import Registry - self.registry = Registry() - testing.setUp(registry=self.registry) + self.config = testing.setUp() def tearDown(self): - del self.registry - testing.tearDown() - - def _registerRenderer(self, typ='.txt'): - from pyramid.interfaces import IRendererFactory - from pyramid.interfaces import ITemplateRenderer - from pyramid.renderers import RendererHelper - from zope.interface import implements - class DummyRenderer: - implements(ITemplateRenderer) - def __init__(self, path): - self.__class__.path = path - def __call__(self, *arg): - return 'Hello!' - self.registry.registerUtility(DummyRenderer, IRendererFactory, name=typ) - renderer = RendererHelper(name='abc' + typ, registry=self.registry) - return renderer - + self.config = None + + def _makeOne(self, **kw): + kw['registry'] = self.config.registry + from pyramid.config import ViewDeriver + return ViewDeriver(**kw) + def _makeRequest(self): request = DummyRequest() - request.registry = self.registry + request.registry = self.config.registry return request - def _callFUT(self, view, **kw): - from pyramid.config import _map_view - return _map_view(view, self.registry, **kw) + def _registerLogger(self): + from pyramid.interfaces import IDebugLogger + logger = DummyLogger() + self.config.registry.registerUtility(logger, IDebugLogger) + return logger - def test__map_view_as_function_context_and_request(self): - def view(context, request): - return 'OK' - result = self._callFUT(view) - self.failUnless(result is view) - self.assertEqual(result(None, None), 'OK') + def _registerSecurityPolicy(self, permissive): + from pyramid.interfaces import IAuthenticationPolicy + from pyramid.interfaces import IAuthorizationPolicy + policy = DummySecurityPolicy(permissive) + self.config.registry.registerUtility(policy, IAuthenticationPolicy) + self.config.registry.registerUtility(policy, IAuthorizationPolicy) - def test__map_view_as_function_with_attr(self): - def view(context, request): - """ """ - result = self._callFUT(view, attr='__name__') + def test_requestonly_function(self): + def view(request): + return 'OK' + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) - self.assertRaises(TypeError, result, None, None) + self.assertEqual(result(None, None), 'OK') - def test__map_view_as_function_with_attr_and_renderer(self): - renderer = self._registerRenderer() - view = lambda *arg: 'OK' - result = self._callFUT(view, attr='__name__', renderer=renderer) + def test_requestonly_function_with_renderer(self): + class moo(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, 'OK') + self.assertEqual(view_inst, view) + self.assertEqual(ctx, context) + return 'moo' + def view(request): + return 'OK' + deriver = self._makeOne(renderer=moo()) + result = deriver(view) self.failIf(result is view) - self.assertRaises(TypeError, result, None, None) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), 'moo') - def test__map_view_as_function_requestonly(self): + def test_requestonly_function_with_renderer_request_has_view(self): + class moo(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, 'OK') + self.assertEqual(view_inst, 'view') + self.assertEqual(ctx, context) + return 'moo' def view(request): return 'OK' - result = self._callFUT(view) + deriver = self._makeOne(renderer=moo()) + result = deriver(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + request.__view__ = 'view' + context = testing.DummyResource() + self.assertEqual(result(context, request), 'moo') + self.failIf(hasattr(request, '__view__')) - def test__map_view_as_function_requestonly_with_attr(self): + def test_class_without_attr(self): + class View(object): + def __init__(self, request): + pass + def __call__(self): + return 'OK' + deriver = self._makeOne() + result = deriver(View) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, View) + + def test_class_with_attr(self): + class View(object): + def __init__(self, request): + pass + def another(self): + return 'OK' + deriver = self._makeOne(attr='another') + result = deriver(View) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, View) + + def test_as_function_context_and_request(self): + def view(context, request): + return 'OK' + deriver = self._makeOne() + result = deriver(view) + self.failUnless(result is view) + self.failIf(hasattr(result, '__call_permissive__')) + self.assertEqual(view(None, None), 'OK') + + def test_as_function_requestonly(self): def view(request): - """ """ - result = self._callFUT(view, attr='__name__') + return 'OK' + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertRaises(TypeError, result, None, None) + self.failIf(hasattr(result, '__call_permissive__')) + self.assertEqual(result(None, None), 'OK') - def test__map_view_as_newstyle_class_context_and_request(self): + def test_as_newstyle_class_context_and_request(self): class view(object): def __init__(self, context, request): pass def __call__(self): return 'OK' - result = self._callFUT(view) + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, view) - def test__map_view_as_newstyle_class_context_and_request_with_attr(self): + def test_as_newstyle_class_requestonly(self): class view(object): def __init__(self, context, request): pass - def index(self): + def __call__(self): return 'OK' - result = self._callFUT(view, attr='index') + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, view) - def test__map_view_as_newstyle_class_context_and_request_attr_and_renderer( - self): - renderer = self._registerRenderer() - class view(object): + def test_as_oldstyle_class_context_and_request(self): + class view: def __init__(self, context, request): pass - def index(self): - return {'a':'1'} - result = self._callFUT(view, attr='index', renderer=renderer) + def __call__(self): + return 'OK' + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, view) - def test__map_view_as_newstyle_class_requestonly(self): - class view(object): - def __init__(self, request): + def test_as_oldstyle_class_requestonly(self): + class view: + def __init__(self, context, request): pass def __call__(self): return 'OK' - result = self._callFUT(view) + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) self.assertEqual(view.__name__, result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + self.assertEqual(request.__view__.__class__, view) + + def test_as_instance_context_and_request(self): + class View: + def __call__(self, context, request): + return 'OK' + view = View() + deriver = self._makeOne() + result = deriver(view) + self.failUnless(result is view) + self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(result(None, None), 'OK') - def test__map_view_as_newstyle_class_requestonly_with_attr(self): - class view(object): - def __init__(self, request): - pass - def index(self): + def test_as_instance_requestonly(self): + class View: + def __call__(self, request): return 'OK' - result = self._callFUT(view, attr='index') + view = View() + deriver = self._makeOne() + result = deriver(view) self.failIf(result is view) self.assertEqual(view.__module__, result.__module__) self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) + self.failUnless('instance' in result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(result(None, None), 'OK') - def test__map_view_as_newstyle_class_requestonly_attr_and_renderer(self): - renderer = self._registerRenderer() - class view(object): + def test_with_debug_authorization_no_authpol(self): + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + logger = self._registerLogger() + deriver = self._makeOne(permission='view') + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + self.assertEqual(result(None, request), 'OK') + self.assertEqual(len(logger.messages), 1) + self.assertEqual(logger.messages[0], + "debug_authorization of url url (view name " + "'view_name' against context None): Allowed " + "(no authorization policy in use)") + + def test_with_debug_authorization_no_permission(self): + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + self._registerSecurityPolicy(True) + logger = self._registerLogger() + deriver = self._makeOne() + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + self.assertEqual(result(None, request), 'OK') + self.assertEqual(len(logger.messages), 1) + self.assertEqual(logger.messages[0], + "debug_authorization of url url (view name " + "'view_name' against context None): Allowed (" + "no permission registered)") + + def test_debug_auth_permission_authpol_permitted(self): + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + logger = self._registerLogger() + self._registerSecurityPolicy(True) + deriver = self._makeOne(permission='view') + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + self.assertEqual(result.__call_permissive__, view) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + self.assertEqual(result(None, request), 'OK') + self.assertEqual(len(logger.messages), 1) + self.assertEqual(logger.messages[0], + "debug_authorization of url url (view name " + "'view_name' against context None): True") + + def test_debug_auth_permission_authpol_denied(self): + from pyramid.exceptions import Forbidden + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + logger = self._registerLogger() + self._registerSecurityPolicy(False) + deriver = self._makeOne(permission='view') + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + self.assertEqual(result.__call_permissive__, view) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + self.assertRaises(Forbidden, result, None, request) + self.assertEqual(len(logger.messages), 1) + self.assertEqual(logger.messages[0], + "debug_authorization of url url (view name " + "'view_name' against context None): False") + + def test_debug_auth_permission_authpol_denied2(self): + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + self._registerLogger() + self._registerSecurityPolicy(False) + deriver = self._makeOne(permission='view') + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + permitted = result.__permitted__(None, None) + self.assertEqual(permitted, False) + + def test_debug_auth_permission_authpol_overridden(self): + view = lambda *arg: 'OK' + self.config.registry.settings = dict( + debug_authorization=True, reload_templates=True) + logger = self._registerLogger() + self._registerSecurityPolicy(False) + deriver = self._makeOne(permission='__no_permission_required__') + result = deriver(view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + self.failIf(hasattr(result, '__call_permissive__')) + request = self._makeRequest() + request.view_name = 'view_name' + request.url = 'url' + self.assertEqual(result(None, request), 'OK') + self.assertEqual(len(logger.messages), 1) + self.assertEqual(logger.messages[0], + "debug_authorization of url url (view name " + "'view_name' against context None): False") + + def test_with_predicates_all(self): + view = lambda *arg: 'OK' + predicates = [] + def predicate1(context, request): + predicates.append(True) + return True + def predicate2(context, request): + predicates.append(True) + return True + deriver = self._makeOne(predicates=[predicate1, predicate2]) + result = deriver(view) + request = self._makeRequest() + request.method = 'POST' + next = result(None, None) + self.assertEqual(next, 'OK') + self.assertEqual(predicates, [True, True]) + + def test_with_predicates_checker(self): + view = lambda *arg: 'OK' + predicates = [] + def predicate1(context, request): + predicates.append(True) + return True + def predicate2(context, request): + predicates.append(True) + return True + deriver = self._makeOne(predicates=[predicate1, predicate2]) + result = deriver(view) + request = self._makeRequest() + request.method = 'POST' + next = result.__predicated__(None, None) + self.assertEqual(next, True) + self.assertEqual(predicates, [True, True]) + + def test_with_predicates_notall(self): + from pyramid.exceptions import NotFound + view = lambda *arg: 'OK' + predicates = [] + def predicate1(context, request): + predicates.append(True) + return True + def predicate2(context, request): + predicates.append(True) + return False + deriver = self._makeOne(predicates=[predicate1, predicate2]) + result = deriver(view) + request = self._makeRequest() + request.method = 'POST' + self.assertRaises(NotFound, result, None, None) + self.assertEqual(predicates, [True, True]) + + def test_with_wrapper_viewname(self): + from webob import Response + from pyramid.interfaces import IView + from pyramid.interfaces import IViewClassifier + inner_response = Response('OK') + def inner_view(context, request): + return inner_response + def outer_view(context, request): + self.assertEqual(request.wrapped_response, inner_response) + self.assertEqual(request.wrapped_body, inner_response.body) + self.assertEqual(request.wrapped_view, inner_view) + return Response('outer ' + request.wrapped_body) + self.config.registry.registerAdapter( + outer_view, (IViewClassifier, None, None), IView, 'owrap') + deriver = self._makeOne(viewname='inner', + wrapper_viewname='owrap') + result = deriver(inner_view) + self.failIf(result is inner_view) + self.assertEqual(inner_view.__module__, result.__module__) + self.assertEqual(inner_view.__doc__, result.__doc__) + request = self._makeRequest() + response = result(None, request) + self.assertEqual(response.body, 'outer OK') + + def test_with_wrapper_viewname_notfound(self): + from webob import Response + inner_response = Response('OK') + def inner_view(context, request): + return inner_response + deriver = self._makeOne(viewname='inner', wrapper_viewname='owrap') + wrapped = deriver(inner_view) + request = self._makeRequest() + self.assertRaises(ValueError, wrapped, None, request) + + def test_as_newstyle_class_context_and_request_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst.__class__, View) + self.assertEqual(ctx, context) + return resp + class View(object): + def __init__(self, context, request): + pass + def index(self): + return {'a':'1'} + deriver = self._makeOne(renderer=renderer(), attr='index') + result = deriver(View) + self.failIf(result is View) + self.assertEqual(result.__module__, View.__module__) + self.assertEqual(result.__doc__, View.__doc__) + self.assertEqual(result.__name__, View.__name__) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) + + def test_as_newstyle_class_requestonly_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst.__class__, View) + self.assertEqual(ctx, context) + return resp + class View(object): + def __init__(self, request): + pass + def index(self): + return {'a':'1'} + deriver = self._makeOne(renderer=renderer(), attr='index') + result = deriver(View) + self.failIf(result is View) + self.assertEqual(result.__module__, View.__module__) + self.assertEqual(result.__doc__, View.__doc__) + self.assertEqual(result.__name__, View.__name__) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) + + def test_as_oldstyle_cls_context_request_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst.__class__, View) + self.assertEqual(ctx, context) + return resp + class View: + def __init__(self, context, request): + pass + def index(self): + return {'a':'1'} + deriver = self._makeOne(renderer=renderer(), attr='index') + result = deriver(View) + self.failIf(result is View) + self.assertEqual(result.__module__, View.__module__) + self.assertEqual(result.__doc__, View.__doc__) + self.assertEqual(result.__name__, View.__name__) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) + + def test_as_oldstyle_cls_requestonly_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst.__class__, View) + self.assertEqual(ctx, context) + return resp + class View: def __init__(self, request): pass def index(self): return {'a':'1'} - result = self._callFUT(view, attr='index', renderer=renderer) + deriver = self._makeOne(renderer=renderer(), attr='index') + result = deriver(View) + self.failIf(result is View) + self.assertEqual(result.__module__, View.__module__) + self.assertEqual(result.__doc__, View.__doc__) + self.assertEqual(result.__name__, View.__name__) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) + + def test_as_instance_context_and_request_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst, view) + self.assertEqual(ctx, context) + return resp + class View: + def index(self, context, request): + return {'a':'1'} + deriver = self._makeOne(renderer=renderer(), attr='index') + view = View() + result = deriver(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) + self.assertEqual(result.__module__, view.__module__) + self.assertEqual(result.__doc__, view.__doc__) + request = self._makeRequest() + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) + + def test_as_instance_requestonly_attr_and_renderer(self): + class renderer(object): + def render_view(inself, req, resp, view_inst, ctx): + self.assertEqual(req, request) + self.assertEqual(resp, {'a':'1'}) + self.assertEqual(view_inst, view) + self.assertEqual(ctx, context) + return resp + class View: + def index(self, request): + return {'a':'1'} + deriver = self._makeOne(renderer=renderer(), attr='index') + view = View() + result = deriver(view) + self.failIf(result is view) + self.assertEqual(result.__module__, view.__module__) + self.assertEqual(result.__doc__, view.__doc__) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + context = testing.DummyResource() + self.assertEqual(result(context, request), {'a':'1'}) - def test__map_view_as_oldstyle_class_context_and_request(self): - class view: +class TestDefaultViewMapper(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + self.registry = self.config.registry + + def tearDown(self): + del self.registry + testing.tearDown() + + def _makeOne(self, **kw): + from pyramid.config import DefaultViewMapper + kw['registry'] = self.registry + return DefaultViewMapper(**kw) + + def _makeRequest(self): + request = DummyRequest() + request.registry = self.registry + return request + + def test_view_as_function_context_and_request(self): + def view(context, request): + return 'OK' + mapper = self._makeOne() + result = mapper(view) + self.failUnless(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test__view_as_function_with_attr(self): + def view(context, request): + """ """ + mapper = self._makeOne(attr='__name__') + result = mapper(view) + self.failIf(result is view) + request = self._makeRequest() + self.assertRaises(TypeError, result, None, request) + + def test_view_as_function_requestonly(self): + def view(request): + return 'OK' + mapper = self._makeOne() + result = mapper(view) + self.failIf(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_function_requestonly_with_attr(self): + def view(request): + """ """ + mapper = self._makeOne(attr='__name__') + result = mapper(view) + self.failIf(result is view) + request = self._makeRequest() + self.assertRaises(TypeError, result, None, request) + + def test_view_as_newstyle_class_context_and_request(self): + class view(object): def __init__(self, context, request): pass def __call__(self): return 'OK' - result = self._callFUT(view) + mapper = self._makeOne() + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_oldstyle_class_context_and_request_with_attr(self): - class view: + def test_view_as_newstyle_class_context_and_request_with_attr(self): + class view(object): def __init__(self, context, request): pass def index(self): return 'OK' - result = self._callFUT(view, attr='index') + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_oldstyle_cls_context_request_attr_and_renderer(self): - renderer = self._registerRenderer() - class view: - def __init__(self, context, request): + def test_view_as_newstyle_class_requestonly(self): + class view(object): + def __init__(self, request): + pass + def __call__(self): + return 'OK' + mapper = self._makeOne() + result = mapper(view) + self.failIf(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_newstyle_class_requestonly_with_attr(self): + class view(object): + def __init__(self, request): pass def index(self): - return {'a':'1'} - result = self._callFUT(view, attr='index', renderer=renderer) + return 'OK' + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_oldstyle_class_requestonly(self): + def test_view_as_oldstyle_class_context_and_request(self): class view: - def __init__(self, request): + def __init__(self, context, request): pass def __call__(self): return 'OK' - result = self._callFUT(view) + mapper = self._makeOne() + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_oldstyle_class_requestonly_with_attr(self): + def test_view_as_oldstyle_class_context_and_request_with_attr(self): class view: - def __init__(self, request): + def __init__(self, context, request): pass def index(self): return 'OK' - result = self._callFUT(view, attr='index') + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') + + def test_view_as_oldstyle_class_requestonly(self): + class view: + def __init__(self, request): + pass + def __call__(self): + return 'OK' + mapper = self._makeOne() + result = mapper(view) + self.failIf(result is view) + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_oldstyle_class_requestonly_attr_and_renderer(self): - renderer = self._registerRenderer() + def test_view_as_oldstyle_class_requestonly_with_attr(self): class view: def __init__(self, request): pass def index(self): - return {'a':'1'} - result = self._callFUT(view, attr='index', renderer=renderer) + return 'OK' + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_instance_context_and_request(self): + def test_view_as_instance_context_and_request(self): class View: def __call__(self, context, request): return 'OK' view = View() - result = self._callFUT(view) + mapper = self._makeOne() + result = mapper(view) self.failUnless(result is view) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_instance_context_and_request_and_attr(self): + def test_view_as_instance_context_and_request_and_attr(self): class View: def index(self, context, request): return 'OK' view = View() - result = self._callFUT(view, attr='index') - self.failIf(result is view) - self.assertEqual(result(None, None), 'OK') - - def test__map_view_as_instance_context_and_request_attr_and_renderer(self): - renderer = self._registerRenderer() - class View: - def index(self, context, request): - return {'a':'1'} - view = View() - result = self._callFUT(view, attr='index', renderer=renderer) + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_instance_requestonly(self): + def test_view_as_instance_requestonly(self): class View: def __call__(self, request): return 'OK' view = View() - result = self._callFUT(view) + mapper = self._makeOne() + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.failUnless('instance' in result.__name__) - self.assertEqual(result(None, None), 'OK') + request = self._makeRequest() + self.assertEqual(result(None, request), 'OK') - def test__map_view_as_instance_requestonly_with_attr(self): + def test_view_as_instance_requestonly_with_attr(self): class View: def index(self, request): return 'OK' view = View() - result = self._callFUT(view, attr='index') + mapper = self._makeOne(attr='index') + result = mapper(view) self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.failUnless('instance' in result.__name__) - self.assertEqual(result(None, None), 'OK') - - def test__map_view_as_instance_requestonly_with_attr_and_renderer(self): - renderer = self._registerRenderer() - class View: - def index(self, request): - return {'a':'1'} - view = View() - result = self._callFUT(view, attr='index', renderer=renderer) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.failUnless('instance' in result.__name__) - request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test__map_view_rendereronly(self): - renderer = self._registerRenderer() - def view(context, request): - return {'a':'1'} - result = self._callFUT(view, renderer=renderer) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test__map_view_with_registry(self): - renderer = self._registerRenderer() - def view(context, request): - return {'a':'1'} - result = self._callFUT(view, renderer=renderer) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) request = self._makeRequest() - self.assertEqual(result(None, request).body, 'Hello!') + self.assertEqual(result(None, request), 'OK') class Test_preserve_view_attrs(unittest.TestCase): def _callFUT(self, view, wrapped_view): @@ -4400,24 +4480,23 @@ class TestMultiView(unittest.TestCase): response = mv(context, request) self.assertEqual(response, expected_response) - -class TestRequestOnly(unittest.TestCase): - def _callFUT(self, arg): +class Test_requestonly(unittest.TestCase): + def _callFUT(self, view, attr=None): from pyramid.config import requestonly - return requestonly(arg) + return requestonly(view, attr) - def test_newstyle_class_no_init(self): + def test_requestonly_newstyle_class_no_init(self): class foo(object): """ """ self.assertFalse(self._callFUT(foo)) - def test_newstyle_class_init_toomanyargs(self): + def test_requestonly_newstyle_class_init_toomanyargs(self): class foo(object): def __init__(self, context, request): """ """ self.assertFalse(self._callFUT(foo)) - def test_newstyle_class_init_onearg_named_request(self): + def test_requestonly_newstyle_class_init_onearg_named_request(self): class foo(object): def __init__(self, request): """ """ @@ -4493,6 +4572,22 @@ class TestRequestOnly(unittest.TestCase): """ """ self.assertFalse(self._callFUT(foo)) + def test_function_with_attr_false(self): + def bar(context, request): + """ """ + def foo(context, request): + """ """ + foo.bar = bar + self.assertFalse(self._callFUT(foo, 'bar')) + + def test_function_with_attr_true(self): + def bar(context, request): + """ """ + def foo(request): + """ """ + foo.bar = bar + self.assertTrue(self._callFUT(foo, 'bar')) + def test_function_onearg_named_request(self): def foo(request): """ """ diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py index 7fc066319..69d74ee6e 100644 --- a/pyramid/tests/test_view.py +++ b/pyramid/tests/test_view.py @@ -229,11 +229,12 @@ class TestViewConfigDecorator(unittest.TestCase): def test_create_nondefaults(self): decorator = self._makeOne(name=None, request_type=None, for_=None, - permission='foo') + permission='foo', view_mapper='mapper') self.assertEqual(decorator.name, None) self.assertEqual(decorator.request_type, None) self.assertEqual(decorator.context, None) self.assertEqual(decorator.permission, 'foo') + self.assertEqual(decorator.view_mapper, 'mapper') def test_call_function(self): decorator = self._makeOne() diff --git a/pyramid/view.py b/pyramid/view.py index 776185d8b..8f201f6d1 100644 --- a/pyramid/view.py +++ b/pyramid/view.py @@ -17,7 +17,6 @@ from zope.interface import providedBy from pyramid.interfaces import IRoutesMapper from pyramid.interfaces import IView from pyramid.interfaces import IViewClassifier -from pyramid.interfaces import IRendererFactory from pyramid.httpexceptions import HTTPFound from pyramid.renderers import RendererHelper @@ -384,7 +383,7 @@ class view_config(object): route_name=None, request_method=None, request_param=None, containment=None, attr=None, renderer=None, wrapper=None, xhr=False, accept=None, header=None, path_info=None, - custom_predicates=(), context=None): + custom_predicates=(), context=None, view_mapper=None): self.name = name self.request_type = request_type self.context = context or for_ @@ -401,6 +400,7 @@ class view_config(object): self.header = header self.path_info = path_info self.custom_predicates = custom_predicates + self.view_mapper = view_mapper def __call__(self, wrapped): settings = self.__dict__.copy() |
