diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-11-16 22:05:17 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-11-16 22:05:17 +0000 |
| commit | e06153d2a851513c435b9f7dc2a5d8f3a1191405 (patch) | |
| tree | f64ffefb1dc6b0894f3a254e919f48148f330b49 | |
| parent | 58fdd1e948b7223cbcaf4fdceb159de200356d79 (diff) | |
| download | pyramid-e06153d2a851513c435b9f7dc2a5d8f3a1191405.tar.gz pyramid-e06153d2a851513c435b9f7dc2a5d8f3a1191405.tar.bz2 pyramid-e06153d2a851513c435b9f7dc2a5d8f3a1191405.zip | |
Failing one test.
| -rw-r--r-- | repoze/bfg/registry.py | 265 | ||||
| -rw-r--r-- | repoze/bfg/renderers.py | 10 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_registry.py | 373 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_view.py | 1049 | ||||
| -rw-r--r-- | repoze/bfg/view.py | 388 |
5 files changed, 1091 insertions, 994 deletions
diff --git a/repoze/bfg/registry.py b/repoze/bfg/registry.py index dfd940af5..95a6d6608 100644 --- a/repoze/bfg/registry.py +++ b/repoze/bfg/registry.py @@ -1,5 +1,9 @@ +import os import re import sys +import inspect + +from webob import Response from zope.component.registry import Components @@ -19,19 +23,30 @@ from repoze.bfg.interfaces import INotFoundView from repoze.bfg.interfaces import IPackageOverrides from repoze.bfg.interfaces import IRendererFactory from repoze.bfg.interfaces import IRequest +from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import IRouteRequest from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import ISecuredView from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IViewPermission - +from repoze.bfg.interfaces import ILogger + +from repoze.bfg import chameleon_zpt +from repoze.bfg import chameleon_text +from repoze.bfg import renderers +from repoze.bfg.compat import all +from repoze.bfg.exceptions import NotFound +from repoze.bfg.exceptions import Forbidden from repoze.bfg.request import route_request_iface from repoze.bfg.resource import PackageOverrides +from repoze.bfg.settings import get_settings from repoze.bfg.static import StaticRootFactory from repoze.bfg.traversal import find_interface -from repoze.bfg.view import MultiView -from repoze.bfg.view import derive_view from repoze.bfg.view import static as static_view +from repoze.bfg.view import render_view_to_response +from repoze.bfg.view import requestonly +from repoze.bfg.view import decorate_view +from repoze.bfg.view import MultiView from repoze.bfg.urldispatch import RoutesRootFactory class Registry(Components, dict): @@ -44,6 +59,10 @@ class Registry(Components, dict): Components.__init__(self, name=name, bases=bases) mapper = RoutesRootFactory(DefaultRootFactory) self.registerUtility(mapper, IRoutesMapper) + self.renderer(chameleon_zpt.renderer_factory, '.pt') + self.renderer(chameleon_text.renderer_factory, '.txt') + self.renderer(renderers.json_renderer_factory, 'json') + self.renderer(renderers.string_renderer_factory, 'string') def registerSubscriptionAdapter(self, *arg, **kw): result = Components.registerSubscriptionAdapter(self, *arg, **kw) @@ -94,8 +113,8 @@ class Registry(Components, dict): request_param=request_param, header=header, accept=accept, containment=containment) - derived_view = derive_view(view, permission, predicates, attr, - renderer, wrapper, name) + derived_view = self.derive_view(view, permission, predicates, attr, + renderer, wrapper, name) r_for_ = for_ r_request_type = request_type if r_for_ is None: @@ -142,6 +161,238 @@ class Registry(Components, dict): (for_, request_type), IViewPermission, name, info=_info) + def map_view(self, view, attr=None, renderer_name=None): + wrapped_view = view + + renderer = None + + if renderer_name is None: + # global default renderer + factory = self.queryUtility(IRendererFactory) + if factory is not None: + renderer_name = '' + renderer = factory(renderer_name) + else: + renderer = self.renderer_from_name(renderer_name) + + if inspect.isclass(view): + # If the object we've located is a class, turn it into a + # function that operates like a Zope view (when it's invoked, + # construct an instance using 'context' and 'request' as + # position arguments, then immediately invoke the __call__ + # method of the instance with no arguments; __call__ should + # return an IResponse). + if requestonly(view, attr): + # its __init__ accepts only a single request argument, + # instead of both context and request + def _bfg_class_requestonly_view(context, request): + inst = view(request) + if attr is None: + response = inst() + else: + response = getattr(inst, attr)() + if renderer is not None: + response = self.rendered_response(renderer, + response, inst, + context, request, + renderer_name) + return response + wrapped_view = _bfg_class_requestonly_view + else: + # its __init__ accepts both context and request + def _bfg_class_view(context, request): + inst = view(context, request) + if attr is None: + response = inst() + else: + response = getattr(inst, attr)() + if renderer is not None: + response = self.rendered_response(renderer, + response, inst, + context, request, + renderer_name) + return response + wrapped_view = _bfg_class_view + + elif requestonly(view, attr): + # its __call__ accepts only a single request argument, + # instead of both context and request + def _bfg_requestonly_view(context, request): + if attr is None: + response = view(request) + else: + response = getattr(view, attr)(request) + + if renderer is not None: + response = self.rendered_response(renderer, + response, view, + context, request, + renderer_name) + return response + wrapped_view = _bfg_requestonly_view + + elif attr: + def _bfg_attr_view(context, request): + response = getattr(view, attr)(context, request) + if renderer is not None: + response = self.rendered_response(renderer, + response, view, + context, request, + renderer_name) + return response + wrapped_view = _bfg_attr_view + + elif renderer is not None: + def _rendered_view(context, request): + response = view(context, request) + response = self.rendered_response(renderer, + response, view, + context, request, + renderer_name) + return response + wrapped_view = _rendered_view + + decorate_view(wrapped_view, view) + return wrapped_view + + def renderer_from_name(self, path): + name = os.path.splitext(path)[1] + if not name: + name = path + factory = self.queryUtility(IRendererFactory, name=name) + if factory is None: + raise ValueError('No renderer for renderer name %r' % name) + return factory(path) + + def rendered_response(self, renderer, response, view, context,request, + renderer_name): + if ( hasattr(response, 'app_iter') and hasattr(response, 'headerlist') + and hasattr(response, 'status') ): + return response + result = renderer(response, {'view':view, 'renderer_name':renderer_name, + 'context':context, 'request':request}) + response_factory = self.queryUtility(IResponseFactory, default=Response) + response = response_factory(result) + attrs = request.__dict__ + content_type = attrs.get('response_content_type', None) + if content_type is not None: + response.content_type = content_type + headerlist = attrs.get('response_headerlist', None) + if headerlist is not None: + for k, v in headerlist: + response.headers.add(k, v) + status = attrs.get('response_status', None) + if status is not None: + response.status = status + charset = attrs.get('response_charset', None) + if charset is not None: + response.charset = charset + cache_for = attrs.get('response_cache_for', None) + if cache_for is not None: + response.cache_expires = cache_for + return response + + def derive_view(self, original_view, permission=None, predicates=(), + attr=None, renderer_name=None, wrapper_viewname=None, + viewname=None): + mapped_view = self.map_view(original_view, attr, renderer_name) + owrapped_view = self.owrap_view(mapped_view, viewname, wrapper_viewname) + secured_view = self.secure_view(owrapped_view, permission) + debug_view = self.authdebug_view(secured_view, permission) + derived_view = self.predicate_wrap(debug_view, predicates) + return derived_view + + def owrap_view(self, view, viewname, wrapper_viewname): + if not wrapper_viewname: + return view + def _owrapped_view(context, request): + response = view(context, request) + request.wrapped_response = response + request.wrapped_body = response.body + request.wrapped_view = view + wrapped_response = render_view_to_response(context, request, + wrapper_viewname) + if wrapped_response is None: + raise ValueError( + 'No wrapper view named %r found when executing view ' + 'named %r' % (wrapper_viewname, viewname)) + return wrapped_response + decorate_view(_owrapped_view, view) + return _owrapped_view + + def predicate_wrap(self, view, predicates): + if not predicates: + return view + def _wrapped(context, request): + if all((predicate(context, request) for predicate in predicates)): + return view(context, request) + raise NotFound('predicate mismatch for view %s' % view) + def checker(context, request): + return all((predicate(context, request) for predicate in + predicates)) + _wrapped.__predicated__ = checker + decorate_view(_wrapped, view) + return _wrapped + + def secure_view(self, view, permission): + wrapped_view = view + authn_policy = self.queryUtility(IAuthenticationPolicy) + authz_policy = self.queryUtility(IAuthorizationPolicy) + if authn_policy and authz_policy and (permission is not None): + def _secured_view(context, request): + principals = authn_policy.effective_principals(request) + if authz_policy.permits(context, principals, permission): + return view(context, request) + msg = getattr(request, 'authdebug_message', + 'Unauthorized: %s failed permission check' % view) + raise Forbidden(msg) + _secured_view.__call_permissive__ = view + def _permitted(context, request): + principals = authn_policy.effective_principals(request) + return authz_policy.permits(context, principals, permission) + _secured_view.__permitted__ = _permitted + wrapped_view = _secured_view + decorate_view(wrapped_view, view) + + return wrapped_view + + def authdebug_view(self, view, permission): + wrapped_view = view + authn_policy = self.queryUtility(IAuthenticationPolicy) + authz_policy = self.queryUtility(IAuthorizationPolicy) + settings = get_settings() + debug_authorization = False + if settings is not None: + debug_authorization = settings.get('debug_authorization', False) + if debug_authorization: + def _authdebug_view(context, request): + view_name = getattr(request, 'view_name', None) + + if authn_policy and authz_policy: + if permission is None: + msg = 'Allowed (no permission registered)' + else: + principals = authn_policy.effective_principals(request) + msg = str(authz_policy.permits(context, principals, + permission)) + else: + msg = 'Allowed (no authorization policy in use)' + + view_name = getattr(request, 'view_name', None) + url = getattr(request, 'url', None) + msg = ('debug_authorization of url %s (view name %r against ' + 'context %r): %s' % (url, view_name, context, msg)) + logger = self.queryUtility(ILogger, 'repoze.bfg.debug') + logger and logger.debug(msg) + if request is not None: + request.authdebug_message = msg + return view(context, request) + + wrapped_view = _authdebug_view + decorate_view(wrapped_view, view) + + return wrapped_view + def route(self, name, path, view=None, view_for=None, permission=None, factory=None, request_type=None, for_=None, header=None, xhr=False, accept=None, path_info=None, @@ -288,8 +539,8 @@ class Registry(Components, dict): raise ConfigurationError('"view" attribute was not specified and ' 'no renderer specified') - derived_view = derive_view(view, attr=attr, renderer_name=renderer, - wrapper_viewname=wrapper) + derived_view = self.derive_view(view, attr=attr, renderer_name=renderer, + wrapper_viewname=wrapper) self.registerUtility(derived_view, iface, '', info=_info) def static(self, name, path, cache_max_age=3600, _info=u''): diff --git a/repoze/bfg/renderers.py b/repoze/bfg/renderers.py index 212c02dcf..b5dfad523 100644 --- a/repoze/bfg/renderers.py +++ b/repoze/bfg/renderers.py @@ -4,7 +4,6 @@ import pkg_resources from zope.component import getSiteManager from zope.component import queryUtility -from repoze.bfg.interfaces import IRendererFactory from repoze.bfg.interfaces import ITemplateRenderer from repoze.bfg.compat import json @@ -63,13 +62,8 @@ def template_renderer_factory(path, impl, level=3): return renderer def renderer_from_name(path): - name = os.path.splitext(path)[1] - if not name: - name = path - factory = queryUtility(IRendererFactory, name=name) - if factory is None: - raise ValueError('No renderer for renderer name %r' % name) - return factory(path) + sm = getSiteManager() + return sm.renderer_from_name(path) def _reload_resources(): settings = get_settings() diff --git a/repoze/bfg/tests/test_registry.py b/repoze/bfg/tests/test_registry.py index 3eada7b1c..11f5cbf3a 100644 --- a/repoze/bfg/tests/test_registry.py +++ b/repoze/bfg/tests/test_registry.py @@ -61,6 +61,355 @@ class TestRegistry(unittest.TestCase): self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')]) self.assertEqual(overrides.package, package) + def _registerRenderer(self, reg, name='.txt'): + from repoze.bfg.interfaces import IRendererFactory + from repoze.bfg.interfaces import ITemplateRenderer + from zope.interface import implements + class Renderer: + implements(ITemplateRenderer) + def __init__(self, path): + pass + def __call__(self, *arg): + return 'Hello!' + reg.registerUtility(Renderer, IRendererFactory, name=name) + + def test_map_view_as_function_context_and_request(self): + def view(context, request): + return 'OK' + reg = self._makeOne() + result = reg.map_view(view) + self.failUnless(result is view) + self.assertEqual(result(None, None), 'OK') + + def test_map_view_as_function_with_attr(self): + def view(context, request): + """ """ + reg = self._makeOne() + result = reg.map_view(view, attr='__name__') + self.failIf(result is view) + self.assertRaises(TypeError, result, None, None) + + def test_map_view_as_function_with_attr_and_renderer(self): + reg = self._makeOne() + self._registerRenderer(reg) + def view(context, request): + """ """ + result = reg.map_view(view, attr='__name__', + renderer_name='fixtures/minimal.txt') + self.failIf(result is view) + self.assertRaises(TypeError, result, None, None) + + def test_map_view_as_function_requestonly(self): + reg = self._makeOne() + def view(request): + return 'OK' + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_function_requestonly_with_attr(self): + reg = self._makeOne() + def view(request): + """ """ + result = reg.map_view(view, attr='__name__') + 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) + + def test_map_view_as_newstyle_class_context_and_request(self): + reg = self._makeOne() + class view(object): + def __init__(self, context, request): + pass + def __call__(self): + return 'OK' + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_newstyle_class_context_and_request_with_attr(self): + reg = self._makeOne() + class view(object): + def __init__(self, context, request): + pass + def index(self): + return 'OK' + result = reg.map_view(view, attr='index') + 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') + + def test_map_view_as_newstyle_class_context_and_request_attr_and_renderer( + self): + reg = self._makeOne() + self._registerRenderer(reg) + class view(object): + def __init__(self, context, request): + pass + def index(self): + return {'a':'1'} + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_as_newstyle_class_requestonly(self): + reg = self._makeOne() + class view(object): + def __init__(self, request): + pass + def __call__(self): + return 'OK' + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_newstyle_class_requestonly_with_attr(self): + reg = self._makeOne() + class view(object): + def __init__(self, request): + pass + def index(self): + return 'OK' + result = reg.map_view(view, attr='index') + 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') + + def test_map_view_as_newstyle_class_requestonly_with_attr_and_renderer(self): + reg = self._makeOne() + self._registerRenderer(reg) + class view(object): + def __init__(self, request): + pass + def index(self): + return {'a':'1'} + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_as_oldstyle_class_context_and_request(self): + reg = self._makeOne() + class view: + def __init__(self, context, request): + pass + def __call__(self): + return 'OK' + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_oldstyle_class_context_and_request_with_attr(self): + reg = self._makeOne() + class view: + def __init__(self, context, request): + pass + def index(self): + return 'OK' + result = reg.map_view(view, attr='index') + 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') + + def test_map_view_as_oldstyle_class_context_and_request_attr_and_renderer( + self): + reg = self._makeOne() + self._registerRenderer(reg) + class view: + def __init__(self, context, request): + pass + def index(self): + return {'a':'1'} + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_as_oldstyle_class_requestonly(self): + reg = self._makeOne() + class view: + def __init__(self, request): + pass + def __call__(self): + return 'OK' + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_oldstyle_class_requestonly_with_attr(self): + reg = self._makeOne() + class view: + def __init__(self, request): + pass + def index(self): + return 'OK' + result = reg.map_view(view, attr='index') + 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') + + def test_map_view_as_oldstyle_class_requestonly_attr_and_renderer(self): + reg = self._makeOne() + self._registerRenderer(reg) + class view: + def __init__(self, request): + pass + def index(self): + return {'a':'1'} + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.assertEqual(view.__name__, result.__name__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_as_instance_context_and_request(self): + reg = self._makeOne() + class View: + def __call__(self, context, request): + return 'OK' + view = View() + result = reg.map_view(view) + self.failUnless(result is view) + self.assertEqual(result(None, None), 'OK') + + def test_map_view_as_instance_context_and_request_and_attr(self): + reg = self._makeOne() + class View: + def index(self, context, request): + return 'OK' + view = View() + result = reg.map_view(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): + reg = self._makeOne() + self._registerRenderer(reg) + class View: + def index(self, context, request): + return {'a':'1'} + view = View() + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_as_instance_requestonly(self): + reg = self._makeOne() + class View: + def __call__(self, request): + return 'OK' + view = View() + result = reg.map_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.assertEqual(result(None, None), 'OK') + + def test_map_view_as_instance_requestonly_with_attr(self): + reg = self._makeOne() + class View: + def index(self, request): + return 'OK' + view = View() + result = reg.map_view(view, attr='index') + 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): + reg = self._makeOne() + self._registerRenderer(reg) + class View: + def index(self, request): + return {'a':'1'} + view = View() + result = reg.map_view( + view, attr='index', + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + self.failUnless('instance' in result.__name__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_rendereronly(self): + reg = self._makeOne() + self._registerRenderer(reg) + def view(context, request): + return {'a':'1'} + result = reg.map_view( + view, + renderer_name='repoze.bfg.tests:fixtures/minimal.txt') + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + + def test_map_view_defaultrendereronly(self): + reg = self._makeOne() + self._registerRenderer(reg, name='') + def view(context, request): + return {'a':'1'} + result = reg.map_view(view) + self.failIf(result is view) + self.assertEqual(view.__module__, result.__module__) + self.assertEqual(view.__doc__, result.__doc__) + request = DummyRequest() + self.assertEqual(result(None, request).body, 'Hello!') + class TestBFGViewGrokker(unittest.TestCase): def setUp(self): cleanUp() @@ -133,7 +482,6 @@ class TestDefaultRootFactory(unittest.TestCase): self.assertEqual(root.a, 1) self.assertEqual(root.b, 2) - class DummyModule: __path__ = "foo" __name__ = "dummy" @@ -157,3 +505,26 @@ class DummyOverrides: def insert(self, path, package, prefix): self.inserted.append((path, package, prefix)) + +class DummyRequest: + def __init__(self, environ=None): + if environ is None: + environ = {} + self.environ = environ + + def get_response(self, application): + return application + + def copy(self): + self.copied = True + return self + +class DummyResponse: + status = '200 OK' + headerlist = () + def __init__(self, body=None): + if body is None: + self.app_iter = () + else: + self.app_iter = [body] + diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py index 80179e247..807dbe85a 100644 --- a/repoze/bfg/tests/test_view.py +++ b/repoze/bfg/tests/test_view.py @@ -526,698 +526,6 @@ class AppendSlashNotFoundView(unittest.TestCase): self.assertEqual(response.status, '302 Found') self.assertEqual(response.location, '/abc/') -class TestMultiView(unittest.TestCase): - def _getTargetClass(self): - from repoze.bfg.view import MultiView - return MultiView - - def _makeOne(self, name='name'): - return self._getTargetClass()(name) - - def test_class_implements_ISecuredView(self): - from zope.interface.verify import verifyClass - from repoze.bfg.interfaces import ISecuredView - verifyClass(ISecuredView, self._getTargetClass()) - - def test_instance_implements_ISecuredView(self): - from zope.interface.verify import verifyObject - from repoze.bfg.interfaces import ISecuredView - verifyObject(ISecuredView, self._makeOne()) - - def test_add(self): - mv = self._makeOne() - mv.add('view', 100) - self.assertEqual(mv.views, [(100, 'view')]) - mv.add('view2', 99) - self.assertEqual(mv.views, [(99, 'view2'), (100, 'view')]) - - def test_match_not_found(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - self.assertRaises(NotFound, mv.match, context, request) - - def test_match_predicate_fails(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - def view(context, request): - """ """ - view.__predicated__ = lambda *arg: False - mv.views = [(100, view)] - context = DummyContext() - request = DummyRequest() - self.assertRaises(NotFound, mv.match, context, request) - - def test_match_predicate_succeeds(self): - mv = self._makeOne() - def view(context, request): - """ """ - view.__predicated__ = lambda *arg: True - mv.views = [(100, view)] - context = DummyContext() - request = DummyRequest() - result = mv.match(context, request) - self.assertEqual(result, view) - - def test_permitted_no_views(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - self.assertRaises(NotFound, mv.__permitted__, context, request) - - def test_permitted_no_match_with__permitted__(self): - mv = self._makeOne() - def view(context, request): - """ """ - mv.views = [(100, view)] - context = DummyContext() - request = DummyRequest() - self.assertEqual(mv.__permitted__(None, None), True) - - def test_permitted(self): - from zope.component import getSiteManager - mv = self._makeOne() - def view(context, request): - """ """ - def permitted(context, request): - return False - view.__permitted__ = permitted - mv.views = [(100, view)] - context = DummyContext() - request = DummyRequest() - sm = getSiteManager() - result = mv.__permitted__(context, request) - self.assertEqual(result, False) - - def test__call__not_found(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - self.assertRaises(NotFound, mv, context, request) - - def test___call__intermediate_not_found(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - request.view_name = '' - expected_response = DummyResponse() - def view1(context, request): - raise NotFound - def view2(context, request): - return expected_response - mv.views = [(100, view1), (99, view2)] - response = mv(context, request) - self.assertEqual(response, expected_response) - - def test___call__(self): - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - request.view_name = '' - expected_response = DummyResponse() - def view(context, request): - return expected_response - mv.views = [(100, view)] - response = mv(context, request) - self.assertEqual(response, expected_response) - - def test__call_permissive__not_found(self): - from repoze.bfg.exceptions import NotFound - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - self.assertRaises(NotFound, mv, context, request) - - def test___call_permissive_has_call_permissive(self): - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - request.view_name = '' - expected_response = DummyResponse() - def view(context, request): - """ """ - def permissive(context, request): - return expected_response - view.__call_permissive__ = permissive - mv.views = [(100, view)] - response = mv.__call_permissive__(context, request) - self.assertEqual(response, expected_response) - - def test___call_permissive_has_no_call_permissive(self): - mv = self._makeOne() - context = DummyContext() - request = DummyRequest() - request.view_name = '' - expected_response = DummyResponse() - def view(context, request): - return expected_response - mv.views = [(100, view)] - response = mv.__call_permissive__(context, request) - self.assertEqual(response, expected_response) - -class Test_map_view(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() - - def _callFUT(self, view, *arg, **kw): - from repoze.bfg.view import map_view - return map_view(view, *arg, **kw) - - def _registerRenderer(self, name='.txt'): - from repoze.bfg.interfaces import IRendererFactory - from repoze.bfg.interfaces import ITemplateRenderer - from zope.interface import implements - from zope.component import getSiteManager - class Renderer: - implements(ITemplateRenderer) - def __init__(self, path): - pass - def __call__(self, *arg): - return 'Hello!' - sm = getSiteManager() - sm.registerUtility(Renderer, IRendererFactory, name=name) - - def test_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 test_view_as_function_with_attr(self): - def view(context, request): - """ """ - result = self._callFUT(view, attr='__name__') - self.failIf(result is view) - self.assertRaises(TypeError, result, None, None) - - def test_view_as_function_with_attr_and_renderer(self): - self._registerRenderer() - def view(context, request): - """ """ - result = self._callFUT(view, attr='__name__', - renderer_name='fixtures/minimal.txt') - self.failIf(result is view) - self.assertRaises(TypeError, result, None, None) - - def test_view_as_function_requestonly(self): - def view(request): - return 'OK' - result = self._callFUT(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') - - def test_view_as_function_requestonly_with_attr(self): - def view(request): - """ """ - result = self._callFUT(view, attr='__name__') - 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) - - 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) - 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') - - 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') - 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') - - def test_view_as_newstyle_class_context_and_request_with_attr_and_renderer( - self): - self._registerRenderer() - class view(object): - def __init__(self, context, request): - pass - def index(self): - return {'a':'1'} - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_as_newstyle_class_requestonly(self): - class view(object): - def __init__(self, request): - pass - def __call__(self): - return 'OK' - result = self._callFUT(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') - - def test_view_as_newstyle_class_requestonly_with_attr(self): - class view(object): - def __init__(self, request): - pass - def index(self): - return 'OK' - result = self._callFUT(view, attr='index') - 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') - - def test_view_as_newstyle_class_requestonly_with_attr_and_renderer(self): - self._registerRenderer() - class view(object): - def __init__(self, request): - pass - def index(self): - return {'a':'1'} - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_as_oldstyle_class_context_and_request(self): - class view: - def __init__(self, context, request): - pass - def __call__(self): - return 'OK' - result = self._callFUT(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') - - def test_view_as_oldstyle_class_context_and_request_with_attr(self): - class view: - def __init__(self, context, request): - pass - def index(self): - return 'OK' - result = self._callFUT(view, attr='index') - 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') - - def test_view_as_oldstyle_class_context_and_request_with_attr_and_renderer( - self): - self._registerRenderer() - class view: - def __init__(self, context, request): - pass - def index(self): - return {'a':'1'} - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_as_oldstyle_class_requestonly(self): - class view: - def __init__(self, request): - pass - def __call__(self): - return 'OK' - result = self._callFUT(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') - - def test_view_as_oldstyle_class_requestonly_with_attr(self): - class view: - def __init__(self, request): - pass - def index(self): - return 'OK' - result = self._callFUT(view, attr='index') - 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') - - def test_view_as_oldstyle_class_requestonly_with_attr_and_renderer(self): - self._registerRenderer() - class view: - def __init__(self, request): - pass - def index(self): - return {'a':'1'} - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.assertEqual(view.__name__, result.__name__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_as_instance_context_and_request(self): - class View: - def __call__(self, context, request): - return 'OK' - view = View() - result = self._callFUT(view) - self.failUnless(result is view) - self.assertEqual(result(None, None), 'OK') - - 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_view_as_instance_context_and_request_attr_and_renderer(self): - self._registerRenderer() - class View: - def index(self, context, request): - return {'a':'1'} - view = View() - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_as_instance_requestonly(self): - class View: - def __call__(self, request): - return 'OK' - view = View() - result = self._callFUT(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_view_as_instance_requestonly_with_attr(self): - class View: - def index(self, request): - return 'OK' - view = View() - result = self._callFUT(view, attr='index') - 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_view_as_instance_requestonly_with_attr_and_renderer(self): - self._registerRenderer() - class View: - def index(self, request): - return {'a':'1'} - view = View() - result = self._callFUT( - view, attr='index', - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - self.failUnless('instance' in result.__name__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_rendereronly(self): - self._registerRenderer() - def view(context, request): - return {'a':'1'} - result = self._callFUT( - view, - renderer_name='repoze.bfg.tests:fixtures/minimal.txt') - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - - def test_view_defaultrendereronly(self): - self._registerRenderer(name='') - def view(context, request): - return {'a':'1'} - result = self._callFUT(view) - self.failIf(result is view) - self.assertEqual(view.__module__, result.__module__) - self.assertEqual(view.__doc__, result.__doc__) - request = DummyRequest() - self.assertEqual(result(None, request).body, 'Hello!') - -class TestRequestOnly(unittest.TestCase): - def _callFUT(self, arg): - from repoze.bfg.view import requestonly - return requestonly(arg) - - def test_newstyle_class_no_init(self): - class foo(object): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_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): - class foo(object): - def __init__(self, request): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_newstyle_class_init_onearg_named_somethingelse(self): - class foo(object): - def __init__(self, req): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_newstyle_class_init_defaultargs_firstname_not_request(self): - class foo(object): - def __init__(self, context, request=None): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_newstyle_class_init_defaultargs_firstname_request(self): - class foo(object): - def __init__(self, request, foo=1, bar=2): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_newstyle_class_init_noargs(self): - class foo(object): - def __init__(): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_oldstyle_class_no_init(self): - class foo: - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_oldstyle_class_init_toomanyargs(self): - class foo: - def __init__(self, context, request): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_oldstyle_class_init_onearg_named_request(self): - class foo: - def __init__(self, request): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_oldstyle_class_init_onearg_named_somethingelse(self): - class foo: - def __init__(self, req): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_oldstyle_class_init_defaultargs_firstname_not_request(self): - class foo: - def __init__(self, context, request=None): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_oldstyle_class_init_defaultargs_firstname_request(self): - class foo: - def __init__(self, request, foo=1, bar=2): - """ """ - self.assertTrue(self._callFUT(foo), True) - - def test_oldstyle_class_init_noargs(self): - class foo: - def __init__(): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_function_toomanyargs(self): - def foo(context, request): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_function_onearg_named_request(self): - def foo(request): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_function_onearg_named_somethingelse(self): - def foo(req): - """ """ - self.assertTrue(self._callFUT(foo)) - - def test_function_defaultargs_firstname_not_request(self): - def foo(context, request=None): - """ """ - self.assertFalse(self._callFUT(foo)) - - def test_function_defaultargs_firstname_request(self): - def foo(request, foo=1, bar=2): - """ """ - self.assertTrue(self._callFUT(foo), True) - - def test_instance_toomanyargs(self): - class Foo: - def __call__(self, context, request): - """ """ - foo = Foo() - self.assertFalse(self._callFUT(foo)) - - def test_instance_defaultargs_onearg_named_request(self): - class Foo: - def __call__(self, request): - """ """ - foo = Foo() - self.assertTrue(self._callFUT(foo)) - - def test_instance_defaultargs_onearg_named_somethingelse(self): - class Foo: - def __call__(self, req): - """ """ - foo = Foo() - self.assertTrue(self._callFUT(foo)) - - def test_instance_defaultargs_firstname_not_request(self): - class Foo: - def __call__(self, context, request=None): - """ """ - foo = Foo() - self.assertFalse(self._callFUT(foo)) - - def test_instance_defaultargs_firstname_request(self): - class Foo: - def __call__(self, request, foo=1, bar=2): - """ """ - foo = Foo() - self.assertTrue(self._callFUT(foo), True) - - def test_instance_nocall(self): - class Foo: pass - foo = Foo() - self.assertFalse(self._callFUT(foo)) - -class TestDecorateView(unittest.TestCase): - def _callFUT(self, wrapped, original): - from repoze.bfg.view import decorate_view - return decorate_view(wrapped, original) - - def test_it_same(self): - def view(context, request): - """ """ - result = self._callFUT(view, view) - self.assertEqual(result, False) - - def test_it_different(self): - class DummyView1: - """ 1 """ - __name__ = '1' - __module__ = '1' - def __call__(self, context, request): - """ """ - def __call_permissive__(self, context, reuqest): - """ """ - def __predicated__(self, context, reuqest): - """ """ - def __permitted__(self, context, request): - """ """ - class DummyView2: - """ 2 """ - __name__ = '2' - __module__ = '2' - def __call__(self, context, request): - """ """ - def __call_permissive__(self, context, reuqest): - """ """ - def __predicated__(self, context, reuqest): - """ """ - def __permitted__(self, context, request): - """ """ - view1 = DummyView1() - view2 = DummyView2() - result = self._callFUT(view1, view2) - self.assertEqual(result, True) - self.failUnless(view1.__doc__ is view2.__doc__) - self.failUnless(view1.__module__ is view2.__module__) - self.failUnless(view1.__name__ is view2.__name__) - self.failUnless(view1.__call_permissive__.im_func is - view2.__call_permissive__.im_func) - self.failUnless(view1.__permitted__.im_func is - view2.__permitted__.im_func) - self.failUnless(view1.__predicated__.im_func is - view2.__predicated__.im_func) - class Test_rendered_response(unittest.TestCase): def setUp(self): cleanUp() @@ -1613,6 +921,363 @@ class TestDeriveView(unittest.TestCase): inner_view, viewname='inner', wrapper_viewname='owrap') result = self.assertRaises(ValueError, wrapped, None, request) +class TestDecorateView(unittest.TestCase): + def _callFUT(self, wrapped, original): + from repoze.bfg.view import decorate_view + return decorate_view(wrapped, original) + + def test_it_same(self): + def view(context, request): + """ """ + result = self._callFUT(view, view) + self.assertEqual(result, False) + + def test_it_different(self): + class DummyView1: + """ 1 """ + __name__ = '1' + __module__ = '1' + def __call__(self, context, request): + """ """ + def __call_permissive__(self, context, reuqest): + """ """ + def __predicated__(self, context, reuqest): + """ """ + def __permitted__(self, context, request): + """ """ + class DummyView2: + """ 2 """ + __name__ = '2' + __module__ = '2' + def __call__(self, context, request): + """ """ + def __call_permissive__(self, context, reuqest): + """ """ + def __predicated__(self, context, reuqest): + """ """ + def __permitted__(self, context, request): + """ """ + view1 = DummyView1() + view2 = DummyView2() + result = self._callFUT(view1, view2) + self.assertEqual(result, True) + self.failUnless(view1.__doc__ is view2.__doc__) + self.failUnless(view1.__module__ is view2.__module__) + self.failUnless(view1.__name__ is view2.__name__) + self.failUnless(view1.__call_permissive__.im_func is + view2.__call_permissive__.im_func) + self.failUnless(view1.__permitted__.im_func is + view2.__permitted__.im_func) + self.failUnless(view1.__predicated__.im_func is + view2.__predicated__.im_func) + +class TestMultiView(unittest.TestCase): + def _getTargetClass(self): + from repoze.bfg.view import MultiView + return MultiView + + def _makeOne(self, name='name'): + return self._getTargetClass()(name) + + def test_class_implements_ISecuredView(self): + from zope.interface.verify import verifyClass + from repoze.bfg.interfaces import ISecuredView + verifyClass(ISecuredView, self._getTargetClass()) + + def test_instance_implements_ISecuredView(self): + from zope.interface.verify import verifyObject + from repoze.bfg.interfaces import ISecuredView + verifyObject(ISecuredView, self._makeOne()) + + def test_add(self): + mv = self._makeOne() + mv.add('view', 100) + self.assertEqual(mv.views, [(100, 'view')]) + mv.add('view2', 99) + self.assertEqual(mv.views, [(99, 'view2'), (100, 'view')]) + + def test_match_not_found(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(NotFound, mv.match, context, request) + + def test_match_predicate_fails(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + def view(context, request): + """ """ + view.__predicated__ = lambda *arg: False + mv.views = [(100, view)] + context = DummyContext() + request = DummyRequest() + self.assertRaises(NotFound, mv.match, context, request) + + def test_match_predicate_succeeds(self): + mv = self._makeOne() + def view(context, request): + """ """ + view.__predicated__ = lambda *arg: True + mv.views = [(100, view)] + context = DummyContext() + request = DummyRequest() + result = mv.match(context, request) + self.assertEqual(result, view) + + def test_permitted_no_views(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(NotFound, mv.__permitted__, context, request) + + def test_permitted_no_match_with__permitted__(self): + mv = self._makeOne() + def view(context, request): + """ """ + mv.views = [(100, view)] + context = DummyContext() + request = DummyRequest() + self.assertEqual(mv.__permitted__(None, None), True) + + def test_permitted(self): + from zope.component import getSiteManager + mv = self._makeOne() + def view(context, request): + """ """ + def permitted(context, request): + return False + view.__permitted__ = permitted + mv.views = [(100, view)] + context = DummyContext() + request = DummyRequest() + sm = getSiteManager() + result = mv.__permitted__(context, request) + self.assertEqual(result, False) + + def test__call__not_found(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(NotFound, mv, context, request) + + def test___call__intermediate_not_found(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + def view1(context, request): + raise NotFound + def view2(context, request): + return expected_response + mv.views = [(100, view1), (99, view2)] + response = mv(context, request) + self.assertEqual(response, expected_response) + + def test___call__(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + def view(context, request): + return expected_response + mv.views = [(100, view)] + response = mv(context, request) + self.assertEqual(response, expected_response) + + def test__call_permissive__not_found(self): + from repoze.bfg.exceptions import NotFound + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + self.assertRaises(NotFound, mv, context, request) + + def test___call_permissive_has_call_permissive(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + def view(context, request): + """ """ + def permissive(context, request): + return expected_response + view.__call_permissive__ = permissive + mv.views = [(100, view)] + response = mv.__call_permissive__(context, request) + self.assertEqual(response, expected_response) + + def test___call_permissive_has_no_call_permissive(self): + mv = self._makeOne() + context = DummyContext() + request = DummyRequest() + request.view_name = '' + expected_response = DummyResponse() + def view(context, request): + return expected_response + mv.views = [(100, view)] + response = mv.__call_permissive__(context, request) + self.assertEqual(response, expected_response) + +class TestRequestOnly(unittest.TestCase): + def _callFUT(self, arg): + from repoze.bfg.view import requestonly + return requestonly(arg) + + def test_newstyle_class_no_init(self): + class foo(object): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_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): + class foo(object): + def __init__(self, request): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_newstyle_class_init_onearg_named_somethingelse(self): + class foo(object): + def __init__(self, req): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_newstyle_class_init_defaultargs_firstname_not_request(self): + class foo(object): + def __init__(self, context, request=None): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_newstyle_class_init_defaultargs_firstname_request(self): + class foo(object): + def __init__(self, request, foo=1, bar=2): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_newstyle_class_init_noargs(self): + class foo(object): + def __init__(): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_oldstyle_class_no_init(self): + class foo: + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_oldstyle_class_init_toomanyargs(self): + class foo: + def __init__(self, context, request): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_oldstyle_class_init_onearg_named_request(self): + class foo: + def __init__(self, request): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_oldstyle_class_init_onearg_named_somethingelse(self): + class foo: + def __init__(self, req): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_oldstyle_class_init_defaultargs_firstname_not_request(self): + class foo: + def __init__(self, context, request=None): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_oldstyle_class_init_defaultargs_firstname_request(self): + class foo: + def __init__(self, request, foo=1, bar=2): + """ """ + self.assertTrue(self._callFUT(foo), True) + + def test_oldstyle_class_init_noargs(self): + class foo: + def __init__(): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_function_toomanyargs(self): + def foo(context, request): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_function_onearg_named_request(self): + def foo(request): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_function_onearg_named_somethingelse(self): + def foo(req): + """ """ + self.assertTrue(self._callFUT(foo)) + + def test_function_defaultargs_firstname_not_request(self): + def foo(context, request=None): + """ """ + self.assertFalse(self._callFUT(foo)) + + def test_function_defaultargs_firstname_request(self): + def foo(request, foo=1, bar=2): + """ """ + self.assertTrue(self._callFUT(foo), True) + + def test_instance_toomanyargs(self): + class Foo: + def __call__(self, context, request): + """ """ + foo = Foo() + self.assertFalse(self._callFUT(foo)) + + def test_instance_defaultargs_onearg_named_request(self): + class Foo: + def __call__(self, request): + """ """ + foo = Foo() + self.assertTrue(self._callFUT(foo)) + + def test_instance_defaultargs_onearg_named_somethingelse(self): + class Foo: + def __call__(self, req): + """ """ + foo = Foo() + self.assertTrue(self._callFUT(foo)) + + def test_instance_defaultargs_firstname_not_request(self): + class Foo: + def __call__(self, context, request=None): + """ """ + foo = Foo() + self.assertFalse(self._callFUT(foo)) + + def test_instance_defaultargs_firstname_request(self): + class Foo: + def __call__(self, request, foo=1, bar=2): + """ """ + foo = Foo() + self.assertTrue(self._callFUT(foo), True) + + def test_instance_nocall(self): + class Foo: pass + foo = Foo() + self.assertFalse(self._callFUT(foo)) + + + class DummyContext: pass diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py index 734bb7f0a..4fc22000b 100644 --- a/repoze/bfg/view.py +++ b/repoze/bfg/view.py @@ -1,8 +1,8 @@ import cgi -import inspect import mimetypes import os import sys +import inspect # See http://bugs.python.org/issue5853 which is a recursion bug # that seems to effect Python 2.6, Python 2.6.1, and 2.6.2 (a fix @@ -26,22 +26,14 @@ from zope.deprecation import deprecated from zope.interface import implements from zope.interface.advice import getFrameInfo -from repoze.bfg.interfaces import IAuthenticationPolicy -from repoze.bfg.interfaces import IAuthorizationPolicy -from repoze.bfg.interfaces import ILogger from repoze.bfg.interfaces import IMultiView -from repoze.bfg.interfaces import IRendererFactory from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import IView -from repoze.bfg.compat import all from repoze.bfg.exceptions import NotFound -from repoze.bfg.exceptions import Forbidden from repoze.bfg.path import caller_package -from repoze.bfg.renderers import renderer_from_name from repoze.bfg.resource import resource_spec -from repoze.bfg.settings import get_settings from repoze.bfg.static import PackageURLParser # b/c imports @@ -477,163 +469,76 @@ def default_forbidden_view(context, request): def default_notfound_view(context, request): return default_view(context, request, '404 Not Found') -class MultiView(object): - implements(IMultiView) +def append_slash_notfound_view(context, request): + """For behavior like Django's ``APPEND_SLASH=True``, use this view + as the Not Found view in your application. - def __init__(self, name): - self.name = name - self.views = [] + When this view is the Not Found view (indicating that no view was + found), and any routes have been defined in the configuration of + your application, if the value of ``PATH_INFO`` does not already + end in a slash, and if the value of ``PATH_INFO`` *plus* a slash + matches any route's path, do an HTTP redirect to the + slash-appended PATH_INFO. Note that this will *lose* ``POST`` + data information (turning it into a GET), so you shouldn't rely on + this to redirect POST requests. - def add(self, view, score): - self.views.append((score, view)) - self.views.sort() + Add the following to your application's ``configure.zcml`` to use + this view as the Not Found view:: - def match(self, context, request): - for score, view in self.views: - if not hasattr(view, '__predicated__'): - return view - if view.__predicated__(context, request): - return view - raise NotFound(self.name) + <notfound + view="repoze.bfg.view.append_slash_notfound_view"/> - def __permitted__(self, context, request): - view = self.match(context, request) - if hasattr(view, '__permitted__'): - return view.__permitted__(context, request) - return True + See also :ref:`changing_the_notfound_view`. - def __call_permissive__(self, context, request): - view = self.match(context, request) - view = getattr(view, '__call_permissive__', view) - return view(context, request) + .. note:: This function is new as of :mod:`repoze.bfg` version 1.1. - def __call__(self, context, request): - for score, view in self.views: - try: - return view(context, request) - except NotFound: - continue - raise NotFound(self.name) + """ + path = request.environ.get('PATH_INFO', '/') + mapper = queryUtility(IRoutesMapper) + if mapper is not None and not path.endswith('/'): + slashpath = path + '/' + for route in mapper.get_routes(): + if route.match(slashpath) is not None: + return HTTPFound(location=slashpath) + return default_view(context, request, '404 Not Found') -def rendered_response(renderer, response, view, context,request, renderer_name): - if ( hasattr(response, 'app_iter') and hasattr(response, 'headerlist') and - hasattr(response, 'status') ): - return response - result = renderer(response, {'view':view, 'renderer_name':renderer_name, - 'context':context, 'request':request}) - response_factory = queryUtility(IResponseFactory, default=Response) - response = response_factory(result) - attrs = request.__dict__ - content_type = attrs.get('response_content_type', None) - if content_type is not None: - response.content_type = content_type - headerlist = attrs.get('response_headerlist', None) - if headerlist is not None: - for k, v in headerlist: - response.headers.add(k, v) - status = attrs.get('response_status', None) - if status is not None: - response.status = status - charset = attrs.get('response_charset', None) - if charset is not None: - response.charset = charset - cache_for = attrs.get('response_cache_for', None) - if cache_for is not None: - response.cache_expires = cache_for - return response +def derive_view(original_view, permission=None, predicates=(), attr=None, + renderer_name=None, wrapper_viewname=None, viewname=None): + sm = getSiteManager() + return sm.derive_view(original_view, permission=permission, + predicates=predicates, attr=attr, + renderer_name=renderer_name, + wrapper_viewname=wrapper_viewname, viewname=viewname) + +def rendered_response(renderer, response, view, context, request, + renderer_name): + sm = getSiteManager() + return sm.rendered_response(renderer, response, view, context, request, + renderer_name) + +def renderer_from_name(self, path): + sm = getSiteManager() + return sm.renderer_from_name(path) def map_view(view, attr=None, renderer_name=None): - wrapped_view = view + sm = getSiteManager() + return sm.map_view(view, attr=attr, renderer_name=renderer_name) + +def owrap_view(view, viewname, wrapper_viewname): + sm = getSiteManager() + return sm.owrap_view(view, viewname, wrapper_viewname) - renderer = None +def predicate_wrap(view, predicates): + sm = getSiteManager() + return sm.predicate_wrap(view, predicates) - if renderer_name is None: - factory = queryUtility(IRendererFactory) # global default renderer - if factory is not None: - renderer_name = '' - renderer = factory(renderer_name) - else: - renderer = renderer_from_name(renderer_name) - - if inspect.isclass(view): - # If the object we've located is a class, turn it into a - # function that operates like a Zope view (when it's invoked, - # construct an instance using 'context' and 'request' as - # position arguments, then immediately invoke the __call__ - # method of the instance with no arguments; __call__ should - # return an IResponse). - if requestonly(view, attr): - # its __init__ accepts only a single request argument, - # instead of both context and request - def _bfg_class_requestonly_view(context, request): - inst = view(request) - if attr is None: - response = inst() - else: - response = getattr(inst, attr)() - if renderer is not None: - response = rendered_response(renderer, - response, inst, - context, request, - renderer_name) - return response - wrapped_view = _bfg_class_requestonly_view - else: - # its __init__ accepts both context and request - def _bfg_class_view(context, request): - inst = view(context, request) - if attr is None: - response = inst() - else: - response = getattr(inst, attr)() - if renderer is not None: - response = rendered_response(renderer, - response, inst, - context, request, - renderer_name) - return response - wrapped_view = _bfg_class_view - - elif requestonly(view, attr): - # its __call__ accepts only a single request argument, - # instead of both context and request - def _bfg_requestonly_view(context, request): - if attr is None: - response = view(request) - else: - response = getattr(view, attr)(request) - - if renderer is not None: - response = rendered_response(renderer, - response, view, - context, request, - renderer_name) - return response - wrapped_view = _bfg_requestonly_view - - elif attr: - def _bfg_attr_view(context, request): - response = getattr(view, attr)(context, request) - if renderer is not None: - response = rendered_response(renderer, - response, view, - context, request, - renderer_name) - return response - wrapped_view = _bfg_attr_view - - elif renderer is not None: - def _rendered_view(context, request): - response = view(context, request) - response = rendered_response(renderer, - response, view, - context, request, - renderer_name) - return response - wrapped_view = _rendered_view - - decorate_view(wrapped_view, view) - return wrapped_view +def secure_view(view, permission): + sm = getSiteManager() + return sm.secure_view(view, permission) + +def authdebug_view(self, view, permission): + sm = getSiteManager() + return sm.authdebug_view(view, permission) def requestonly(class_or_callable, attr=None): """ Return true of the class or callable accepts only a request argument, @@ -678,6 +583,44 @@ def requestonly(class_or_callable, attr=None): return False +class MultiView(object): + implements(IMultiView) + + def __init__(self, name): + self.name = name + self.views = [] + + def add(self, view, score): + self.views.append((score, view)) + self.views.sort() + + def match(self, context, request): + for score, view in self.views: + if not hasattr(view, '__predicated__'): + return view + if view.__predicated__(context, request): + return view + raise NotFound(self.name) + + def __permitted__(self, context, request): + view = self.match(context, request) + if hasattr(view, '__permitted__'): + return view.__permitted__(context, request) + return True + + def __call_permissive__(self, context, request): + view = self.match(context, request) + view = getattr(view, '__call_permissive__', view) + return view(context, request) + + def __call__(self, context, request): + for score, view in self.views: + try: + return view(context, request) + except NotFound: + continue + raise NotFound(self.name) + def decorate_view(wrapped_view, original_view): if wrapped_view is not original_view: wrapped_view.__module__ = original_view.__module__ @@ -691,7 +634,8 @@ def decorate_view(wrapped_view, original_view): except AttributeError: pass try: - wrapped_view.__call_permissive__ = original_view.__call_permissive__ + wrapped_view.__call_permissive__ = \ + original_view.__call_permissive__ except AttributeError: pass try: @@ -701,134 +645,6 @@ def decorate_view(wrapped_view, original_view): return True return False -def derive_view(original_view, permission=None, predicates=(), attr=None, - renderer_name=None, wrapper_viewname=None, viewname=None): - mapped_view = map_view(original_view, attr, renderer_name) - owrapped_view = owrap_view(mapped_view, viewname, wrapper_viewname) - secured_view = secure_view(owrapped_view, permission) - debug_view = authdebug_view(secured_view, permission) - derived_view = predicate_wrap(debug_view, predicates) - return derived_view - -def owrap_view(view, viewname, wrapper_viewname): - if not wrapper_viewname: - return view - def _owrapped_view(context, request): - response = view(context, request) - request.wrapped_response = response - request.wrapped_body = response.body - request.wrapped_view = view - wrapped_response = render_view_to_response(context, request, - wrapper_viewname) - if wrapped_response is None: - raise ValueError( - 'No wrapper view named %r found when executing view named %r' % - (wrapper_viewname, viewname)) - return wrapped_response - decorate_view(_owrapped_view, view) - return _owrapped_view - -def predicate_wrap(view, predicates): - if not predicates: - return view - def _wrapped(context, request): - if all((predicate(context, request) for predicate in predicates)): - return view(context, request) - raise NotFound('predicate mismatch for view %s' % view) - def checker(context, request): - return all((predicate(context, request) for predicate in predicates)) - _wrapped.__predicated__ = checker - decorate_view(_wrapped, view) - return _wrapped - -def secure_view(view, permission): - wrapped_view = view - authn_policy = queryUtility(IAuthenticationPolicy) - authz_policy = queryUtility(IAuthorizationPolicy) - if authn_policy and authz_policy and (permission is not None): - def _secured_view(context, request): - principals = authn_policy.effective_principals(request) - if authz_policy.permits(context, principals, permission): - return view(context, request) - msg = getattr(request, 'authdebug_message', - 'Unauthorized: %s failed permission check' % view) - raise Forbidden(msg) - _secured_view.__call_permissive__ = view - def _permitted(context, request): - principals = authn_policy.effective_principals(request) - return authz_policy.permits(context, principals, permission) - _secured_view.__permitted__ = _permitted - wrapped_view = _secured_view - decorate_view(wrapped_view, view) - - return wrapped_view - -def authdebug_view(view, permission): - wrapped_view = view - authn_policy = queryUtility(IAuthenticationPolicy) - authz_policy = queryUtility(IAuthorizationPolicy) - settings = get_settings() - debug_authorization = False - if settings is not None: - debug_authorization = settings.get('debug_authorization', False) - if debug_authorization: - def _authdebug_view(context, request): - view_name = getattr(request, 'view_name', None) - - if authn_policy and authz_policy: - if permission is None: - msg = 'Allowed (no permission registered)' - else: - principals = authn_policy.effective_principals(request) - msg = str(authz_policy.permits(context, principals, - permission)) - else: - msg = 'Allowed (no authorization policy in use)' - - view_name = getattr(request, 'view_name', None) - url = getattr(request, 'url', None) - msg = ('debug_authorization of url %s (view name %r against ' - 'context %r): %s' % (url, view_name, context, msg)) - logger = queryUtility(ILogger, 'repoze.bfg.debug') - logger and logger.debug(msg) - if request is not None: - request.authdebug_message = msg - return view(context, request) - - wrapped_view = _authdebug_view - decorate_view(wrapped_view, view) - - return wrapped_view - -def append_slash_notfound_view(context, request): - """For behavior like Django's ``APPEND_SLASH=True``, use this view - as the Not Found view in your application. - - When this view is the Not Found view (indicating that no view was - found), and any routes have been defined in the configuration of - your application, if the value of ``PATH_INFO`` does not already - end in a slash, and if the value of ``PATH_INFO`` *plus* a slash - matches any route's path, do an HTTP redirect to the - slash-appended PATH_INFO. Note that this will *lose* ``POST`` - data information (turning it into a GET), so you shouldn't rely on - this to redirect POST requests. - - Add the following to your application's ``configure.zcml`` to use - this view as the Not Found view:: - - <notfound - view="repoze.bfg.view.append_slash_notfound_view"/> - See also :ref:`changing_the_notfound_view`. - - .. note:: This function is new as of :mod:`repoze.bfg` version 1.1. - - """ - path = request.environ.get('PATH_INFO', '/') - mapper = queryUtility(IRoutesMapper) - if mapper is not None and not path.endswith('/'): - slashpath = path + '/' - for route in mapper.get_routes(): - if route.match(slashpath) is not None: - return HTTPFound(location=slashpath) - return default_view(context, request, '404 Not Found') + + |
