diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-11-19 11:26:23 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-11-19 11:26:23 +0000 |
| commit | a32d2a29df8948694efc78e2d30e7059f80deff7 (patch) | |
| tree | fdb69b2d594429fef84f6f65c6abbe0ccad08c10 | |
| parent | eac7c470021b647d63c2e2af8acd6cebd738f2a4 (diff) | |
| download | pyramid-a32d2a29df8948694efc78e2d30e7059f80deff7.tar.gz pyramid-a32d2a29df8948694efc78e2d30e7059f80deff7.tar.bz2 pyramid-a32d2a29df8948694efc78e2d30e7059f80deff7.zip | |
- The ``repoze.bfg.view.rendered_response`` function has been moved to
``repoze.bfg.configuration.rendered_response``.
- The ``repoze.bfg.view.decorate_view`` function has been moved to
``repoze.bfg.configuration.decorate_view``.
- The ``repoze.bfg.view.MultiView`` class has been moved to
``repoze.bfg.configuration.MultiView``.
- Fix argument ordering bug in r.b.configuration.Configurator.resource.
| -rw-r--r-- | CHANGES.txt | 12 | ||||
| -rw-r--r-- | repoze/bfg/configuration.py | 145 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 2 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_configuration.py | 460 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 7 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_view.py | 442 | ||||
| -rw-r--r-- | repoze/bfg/view.py | 136 |
7 files changed, 599 insertions, 605 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index a60e2aaa0..2de872afe 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -25,6 +25,18 @@ Internals Its job has been subsumed by the ``repoze.bfg.settings.Settings`` class constructor. +- The ``repoze.bfg.view.requestonly`` function has been moved to + ``repoze.bfg.configuration.requestonly``. + +- The ``repoze.bfg.view.rendered_response`` function has been moved to + ``repoze.bfg.configuration.rendered_response``. + +- The ``repoze.bfg.view.decorate_view`` function has been moved to + ``repoze.bfg.configuration.decorate_view``. + +- The ``repoze.bfg.view.MultiView`` class has been moved to + ``repoze.bfg.configuration.MultiView``. + Backwards Incompatibilites -------------------------- diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index 447cb5963..0c64d7411 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -4,6 +4,8 @@ import sys import threading import inspect +from webob import Response + import zope.component from zope.component.event import dispatch @@ -12,10 +14,12 @@ from zope.configuration import xmlconfig from zope.component import getGlobalSiteManager from zope.component import getSiteManager +from zope.component import queryUtility from zope.interface import Interface from zope.interface import implementedBy from zope.interface.interfaces import IInterface +from zope.interface import implements from repoze.bfg.interfaces import IAuthenticationPolicy from repoze.bfg.interfaces import IAuthorizationPolicy @@ -27,6 +31,7 @@ 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 IRootFactory from repoze.bfg.interfaces import IRouteRequest from repoze.bfg.interfaces import IRoutesMapper @@ -54,11 +59,7 @@ from repoze.bfg.threadlocal import manager from repoze.bfg.traversal import find_interface from repoze.bfg.traversal import DefaultRootFactory from repoze.bfg.urldispatch import RoutesMapper -from repoze.bfg.view import MultiView -from repoze.bfg.view import decorate_view -from repoze.bfg.view import rendered_response from repoze.bfg.view import render_view_to_response -from repoze.bfg.view import requestonly from repoze.bfg.view import static as static_view import martian @@ -508,8 +509,7 @@ class Configurator(object): iface = ITemplateRendererFactory self.reg.registerUtility(factory, iface, name=name, info=_info) - def resource(self, to_override, override_with, _override=None, - _info=u''): + def resource(self, to_override, override_with, _info=u'', _override=None,): if to_override == override_with: raise ConfigurationError('You cannot override a resource with ' 'itself') @@ -716,3 +716,136 @@ class BFGViewGrokker(martian.InstanceGrokker): config.view(view=obj, _info=info, **settings) return bool(config) +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 original_view: + return False + wrapped_view.__module__ = original_view.__module__ + wrapped_view.__doc__ = original_view.__doc__ + try: + wrapped_view.__name__ = original_view.__name__ + except AttributeError: + wrapped_view.__name__ = repr(original_view) + try: + wrapped_view.__permitted__ = original_view.__permitted__ + except AttributeError: + pass + try: + wrapped_view.__call_permissive__ = original_view.__call_permissive__ + except AttributeError: + pass + try: + wrapped_view.__predicated__ = original_view.__predicated__ + except AttributeError: + pass + return True + +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) + if request is not None: # in tests, it may be None + 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 requestonly(class_or_callable, attr=None): + """ Return true of the class or callable accepts only a request argument, + as opposed to something that accepts context, request """ + if attr is None: + attr = '__call__' + if inspect.isfunction(class_or_callable): + fn = class_or_callable + elif inspect.isclass(class_or_callable): + try: + fn = class_or_callable.__init__ + except AttributeError: + return False + else: + try: + fn = getattr(class_or_callable, attr) + except AttributeError: + return False + + try: + argspec = inspect.getargspec(fn) + except TypeError: + 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: + return False + + if len(args) == 1: + return True + + elif args[0] == 'request': + if len(args) - len(defaults) == 1: + return True + + return False + diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index 7edf40620..a46232330 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -190,7 +190,7 @@ def make_app(root_factory, package=None, filename='configure.zcml', ``settings`` keyword parameter. """ if Configurator is None: - from repoze.bfg.configuration import Configurator + from repoze.bfg.configuration import Configurator # pragma: no cover settings = settings or options config = Configurator() config.declarative(root_factory, package=package, diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index a1f60a91f..d2a9ca75f 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -1154,7 +1154,6 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(result(None, request).body, 'Hello!') def test_default_config_fixtureapp_default_filename_withpackage(self): - manager = DummyRegistryManager() from repoze.bfg.tests import fixtureapp rootfactory = DummyRootFactory(None) registry = self._callDefaultConfiguration(rootfactory, fixtureapp) @@ -1220,7 +1219,6 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(settings.mysetting, True) def test_declarative_registrations(self): - manager = DummyRegistryManager() settings = {'reload_templates':True, 'debug_authorization':True} from repoze.bfg.tests import fixtureapp @@ -1313,19 +1311,450 @@ class TestBFGViewGrokker(unittest.TestCase): result = grokker.grok('name', obj) self.assertEqual(result, False) -class DummyRequest: - pass +class Test_rendered_response(unittest.TestCase): + def setUp(self): + cleanUp() + + def tearDown(self): + cleanUp() + + def _callFUT(self, renderer, response, view=None, + context=None, request=None, renderer_name=None): + from repoze.bfg.configuration import rendered_response + if request is None: + request = DummyRequest() + return rendered_response(renderer, response, view, + context, request, renderer_name) + + def _makeRenderer(self): + def renderer(*arg): + return 'Hello!' + return renderer + + def test_is_response(self): + renderer = self._makeRenderer() + response = DummyResponse() + result = self._callFUT(renderer, response) + self.assertEqual(result, response) + + def test_calls_renderer(self): + renderer = self._makeRenderer() + response = {'a':'1'} + result = self._callFUT(renderer, response) + self.assertEqual(result.body, 'Hello!') + + def test_with_content_type(self): + renderer = self._makeRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_content_type':'text/nonsense'} + request.__dict__.update(attrs) + result = self._callFUT(renderer, response, request=request) + self.assertEqual(result.content_type, 'text/nonsense') + + def test_with_headerlist(self): + renderer = self._makeRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_headerlist':[('a', '1'), ('b', '2')]} + request.__dict__.update(attrs) + result = self._callFUT(renderer, response, request=request) + self.assertEqual(result.headerlist, + [('Content-Type', 'text/html; charset=UTF-8'), + ('Content-Length', '6'), + ('a', '1'), + ('b', '2')]) + + def test_with_status(self): + renderer = self._makeRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_status':'406 You Lose'} + request.__dict__.update(attrs) + result = self._callFUT(renderer, response, request=request) + self.assertEqual(result.status, '406 You Lose') + + def test_with_charset(self): + renderer = self._makeRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_charset':'UTF-16'} + request.__dict__.update(attrs) + result = self._callFUT(renderer, response, request=request) + self.assertEqual(result.charset, 'UTF-16') + + def test_with_cache_for(self): + renderer = self._makeRenderer() + response = {'a':'1'} + request = DummyRequest() + attrs = {'response_cache_for':100} + request.__dict__.update(attrs) + result = self._callFUT(renderer, response, request=request) + self.assertEqual(result.cache_control.max_age, 100) + +class Test_decorate_view(unittest.TestCase): + def _callFUT(self, wrapped, original): + from repoze.bfg.configuration 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.configuration 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) -class DummyRegistryManager: - def push(self, registry): - from repoze.bfg.threadlocal import manager - manager.push(registry) - self.pushed = True + 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 pop(self): - from repoze.bfg.threadlocal import manager - manager.pop() - self.popped = True + 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.configuration 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)) + + def test_function_noargs(self): + def foo(): + """ """ + self.assertFalse(self._callFUT(foo)) + + 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 DummyRequest: + pass class DummyRootFactory: def __init__(self, root): @@ -1359,3 +1788,8 @@ class IDummy(Interface): class IOther(Interface): pass + +class DummyResponse: + status = '200 OK' + headerlist = () + app_iter = () diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py index f3fe6dd70..e747a26e6 100644 --- a/repoze/bfg/tests/test_router.py +++ b/repoze/bfg/tests/test_router.py @@ -612,13 +612,6 @@ class DummyLogger: warn = info debug = info -class DummyRegistryManager: - def push(self, registry): - self.pushed = True - - def pop(self): - self.popped = True - class DummyConfigurator(object): def make_wsgi_app(self): return self diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py index e06f6225f..c293394c1 100644 --- a/repoze/bfg/tests/test_view.py +++ b/repoze/bfg/tests/test_view.py @@ -526,86 +526,6 @@ class AppendSlashNotFoundView(unittest.TestCase): self.assertEqual(response.status, '302 Found') self.assertEqual(response.location, '/abc/') -class Test_rendered_response(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() - - def _callFUT(self, renderer, response, view=None, - context=None, request=None, renderer_name=None): - from repoze.bfg.view import rendered_response - if request is None: - request = DummyRequest() - return rendered_response(renderer, response, view, - context, request, renderer_name) - - def _makeRenderer(self): - def renderer(*arg): - return 'Hello!' - return renderer - - def test_is_response(self): - renderer = self._makeRenderer() - response = DummyResponse() - result = self._callFUT(renderer, response) - self.assertEqual(result, response) - - def test_calls_renderer(self): - renderer = self._makeRenderer() - response = {'a':'1'} - result = self._callFUT(renderer, response) - self.assertEqual(result.body, 'Hello!') - - def test_with_content_type(self): - renderer = self._makeRenderer() - response = {'a':'1'} - request = DummyRequest() - attrs = {'response_content_type':'text/nonsense'} - request.__dict__.update(attrs) - result = self._callFUT(renderer, response, request=request) - self.assertEqual(result.content_type, 'text/nonsense') - - def test_with_headerlist(self): - renderer = self._makeRenderer() - response = {'a':'1'} - request = DummyRequest() - attrs = {'response_headerlist':[('a', '1'), ('b', '2')]} - request.__dict__.update(attrs) - result = self._callFUT(renderer, response, request=request) - self.assertEqual(result.headerlist, - [('Content-Type', 'text/html; charset=UTF-8'), - ('Content-Length', '6'), - ('a', '1'), - ('b', '2')]) - - def test_with_status(self): - renderer = self._makeRenderer() - response = {'a':'1'} - request = DummyRequest() - attrs = {'response_status':'406 You Lose'} - request.__dict__.update(attrs) - result = self._callFUT(renderer, response, request=request) - self.assertEqual(result.status, '406 You Lose') - - def test_with_charset(self): - renderer = self._makeRenderer() - response = {'a':'1'} - request = DummyRequest() - attrs = {'response_charset':'UTF-16'} - request.__dict__.update(attrs) - result = self._callFUT(renderer, response, request=request) - self.assertEqual(result.charset, 'UTF-16') - - def test_with_cache_for(self): - renderer = self._makeRenderer() - response = {'a':'1'} - request = DummyRequest() - attrs = {'response_cache_for':100} - request.__dict__.update(attrs) - result = self._callFUT(renderer, response, request=request) - self.assertEqual(result.cache_control.max_age, 100) class TestDeriveView(unittest.TestCase): def setUp(self): @@ -921,368 +841,6 @@ 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)) - - def test_function_noargs(self): - def foo(): - """ """ - self.assertFalse(self._callFUT(foo)) - - 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 43ad809c1..8ef8f3bb6 100644 --- a/repoze/bfg/view.py +++ b/repoze/bfg/view.py @@ -2,7 +2,6 @@ import cgi 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 @@ -23,15 +22,12 @@ from zope.component import getSiteManager from zope.component import providedBy from zope.component import queryUtility from zope.deprecation import deprecated -from zope.interface import implements from zope.interface.advice import getFrameInfo -from repoze.bfg.interfaces import IMultiView from repoze.bfg.interfaces import IResponseFactory from repoze.bfg.interfaces import IRoutesMapper from repoze.bfg.interfaces import IView -from repoze.bfg.exceptions import NotFound from repoze.bfg.path import caller_package from repoze.bfg.resource import resource_spec from repoze.bfg.static import PackageURLParser @@ -513,135 +509,3 @@ def derive_view(original_view, permission=None, predicates=(), attr=None, wrapper_viewname=wrapper_viewname, viewname=viewname) -def requestonly(class_or_callable, attr=None): - """ Return true of the class or callable accepts only a request argument, - as opposed to something that accepts context, request """ - if attr is None: - attr = '__call__' - if inspect.isfunction(class_or_callable): - fn = class_or_callable - elif inspect.isclass(class_or_callable): - try: - fn = class_or_callable.__init__ - except AttributeError: - return False - else: - try: - fn = getattr(class_or_callable, attr) - except AttributeError: - return False - - try: - argspec = inspect.getargspec(fn) - except TypeError: - 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: - return False - - if len(args) == 1: - return True - - elif args[0] == 'request': - if len(args) - len(defaults) == 1: - return True - - 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 original_view: - return False - wrapped_view.__module__ = original_view.__module__ - wrapped_view.__doc__ = original_view.__doc__ - try: - wrapped_view.__name__ = original_view.__name__ - except AttributeError: - wrapped_view.__name__ = repr(original_view) - try: - wrapped_view.__permitted__ = original_view.__permitted__ - except AttributeError: - pass - try: - wrapped_view.__call_permissive__ = original_view.__call_permissive__ - except AttributeError: - pass - try: - wrapped_view.__predicated__ = original_view.__predicated__ - except AttributeError: - pass - return True - -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) - if request is not None: # in tests, it may be None - 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 |
