From eecdbc34962b00e35d41039af014462cf558acee Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 3 Jan 2010 03:39:30 +0000 Subject: Features -------- - The ``Configurator.add_view`` method now accepts an argument named ``context``. This is an alias for the older argument named ``for_``; it is preferred over ``for_``, but ``for_`` will continue to be supported "forever". - The ``view`` ZCML directive now accepts an attribute named ``context``. This is an alias for the older attribute named ``for``; it is preferred over ``for``, but ``for`` will continue to be supported "forever". - The ``Configurator.add_route`` method now accepts an argument named ``view_context``. This is an alias for the older argument named ``view_for``; it is preferred over ``view_for``, but ``view_for`` will continue to be supported "forever". - The ``route`` ZCML directive now accepts an attribute named ``view_context``. This is an alias for the older attribute named ``view_for``; it is preferred over ``view_for``, but ``view_for`` will continue to be supported "forever". Documentation and Paster Templates ---------------------------------- - All uses of the ``Configurator.add_view`` method that used its ``for_`` argument now use the ``context``argument instead. - All uses of the ``Configurator.add_route`` method that used its ``view_for`` argument now use the ``view_context``argument instead. - All uses of the ``view`` ZCML directive that used its ``for`` attribute now use the ``context`` attribute instead. - All uses of the ``route`` ZCML directive that used its ``view_for`` attribute now use the ``view_context`` attribute instead. --- repoze/bfg/configuration.py | 45 ++++++++----- .../alchemy/+package+/configure.zcml | 4 +- .../starter/+package+/configure.zcml | 2 +- .../paster_templates/zodb/+package+/configure.zcml | 2 +- repoze/bfg/tests/test_configuration.py | 43 +++++++++++- repoze/bfg/tests/test_view.py | 10 +-- repoze/bfg/tests/test_zcml.py | 78 ++++++++++++++++++++++ repoze/bfg/view.py | 15 +++-- repoze/bfg/zcml.py | 30 ++++++--- 9 files changed, 186 insertions(+), 43 deletions(-) (limited to 'repoze') diff --git a/repoze/bfg/configuration.py b/repoze/bfg/configuration.py index bce8be232..5fd5b5b1b 100644 --- a/repoze/bfg/configuration.py +++ b/repoze/bfg/configuration.py @@ -431,7 +431,8 @@ class Configurator(object): request_type=None, route_name=None, request_method=None, request_param=None, containment=None, attr=None, renderer=None, wrapper=None, xhr=False, accept=None, - header=None, path_info=None, custom_predicates=(), _info=u''): + header=None, path_info=None, custom_predicates=(), + context=None, _info=u''): """ Add a :term:`view configuration` to the current configuration state. Arguments to ``add_view`` are broken down below into *predicate* arguments and *non-predicate* @@ -535,7 +536,7 @@ class Configurator(object): The :term:`view name`. Read :ref:`traversal_chapter` to understand the concept of a view name. - for + context An object representing Python class that the :term:`context` must be an instance of, *or* the :term:`interface` that the @@ -543,7 +544,9 @@ class Configurator(object): found and called. This predicate is true when the :term:`context` is an instance of the represented class or if the :term:`context` provides the represented interface; - it is otherwise false. + it is otherwise false. This argument may also be provided + to ``add_view`` as ``for_`` (an older, still-supported + spelling). route_name @@ -701,12 +704,16 @@ class Configurator(object): derived_view = self._derive_view(view, permission, predicates, attr, renderer, wrapper, name, accept) - r_for_ = for_ + + if context is None: + context = for_ + + r_context = context r_request_type = request_type - if r_for_ is None: - r_for_ = Interface - if not IInterface.providedBy(r_for_): - r_for_ = implementedBy(r_for_) + if r_context is None: + r_context = Interface + if not IInterface.providedBy(r_context): + r_context = implementedBy(r_context) if not IInterface.providedBy(r_request_type): r_request_type = implementedBy(r_request_type) @@ -733,7 +740,7 @@ class Configurator(object): old_view = None for view_type in (IView, ISecuredView, IMultiView): - old_view = registered((r_for_, r_request_type), view_type, name) + old_view = registered((r_context, r_request_type), view_type, name) if old_view is not None: break @@ -745,7 +752,7 @@ class Configurator(object): view_iface = ISecuredView else: view_iface = IView - self.registry.registerAdapter(derived_view, (for_, request_type), + self.registry.registerAdapter(derived_view, (context, request_type), view_iface, name, info=_info) else: # XXX we could try to be more efficient here and register @@ -763,8 +770,8 @@ class Configurator(object): for view_type in (IView, ISecuredView): # unregister any existing views self.registry.adapters.unregister( - (r_for_, r_request_type), view_type, name=name) - self.registry.registerAdapter(multiview, (for_, request_type), + (r_context, r_request_type), view_type, name=name) + self.registry.registerAdapter(multiview, (context, request_type), IMultiView, name, info=_info) def add_route(self, name, path, view=None, view_for=None, @@ -777,7 +784,8 @@ class Configurator(object): view_containment=None, view_attr=None, renderer=None, view_renderer=None, view_header=None, view_accept=None, view_xhr=False, - view_path_info=None, _info=u''): + view_path_info=None, view_context=None, + _info=u''): """ Add a :term:`route configuration` to the current configuration state, as well as possibly a :term:`view configuration` to be used to specify a :term:`view callable` @@ -910,7 +918,7 @@ class Configurator(object): callable when this route matches. e.g. ``mypackage.views.my_view``. - view_for + view_context A reference to a class or an :term:`interface` that the :term:`context` of the view should match for the view named @@ -921,7 +929,7 @@ class Configurator(object): If the ``view`` argument is not provided, this argument has no effect. - This attribute can also be spelled as ``for_``. + This attribute can also be spelled as ``for_`` or ``view_for``. view_permission @@ -1017,12 +1025,15 @@ class Configurator(object): request_iface, IRouteRequest, name=name) if view: - view_for = view_for or for_ + if view_context is None: + view_context = view_for + if view_context is None: + view_context = for_ view_permission = view_permission or permission view_renderer = view_renderer or renderer self.add_view( permission=view_permission, - for_=view_for, + context=view_context, view=view, name='', route_name=name, diff --git a/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml b/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml index 1c8f26e62..40b863c62 100644 --- a/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml +++ b/repoze/bfg/paster_templates/alchemy/+package+/configure.zcml @@ -4,13 +4,13 @@ diff --git a/repoze/bfg/paster_templates/starter/+package+/configure.zcml b/repoze/bfg/paster_templates/starter/+package+/configure.zcml index 038f04da4..e83dd3933 100644 --- a/repoze/bfg/paster_templates/starter/+package+/configure.zcml +++ b/repoze/bfg/paster_templates/starter/+package+/configure.zcml @@ -4,7 +4,7 @@ diff --git a/repoze/bfg/paster_templates/zodb/+package+/configure.zcml b/repoze/bfg/paster_templates/zodb/+package+/configure.zcml index 038f04da4..e83dd3933 100644 --- a/repoze/bfg/paster_templates/zodb/+package+/configure.zcml +++ b/repoze/bfg/paster_templates/zodb/+package+/configure.zcml @@ -4,7 +4,7 @@ diff --git a/repoze/bfg/tests/test_configuration.py b/repoze/bfg/tests/test_configuration.py index d8b6aca99..ba306f26b 100644 --- a/repoze/bfg/tests/test_configuration.py +++ b/repoze/bfg/tests/test_configuration.py @@ -492,7 +492,26 @@ class ConfiguratorTests(unittest.TestCase): result = wrapper(None, None) self.assertEqual(result, 'OK') + def test_add_view_context_as_class(self): + from zope.interface import implementedBy + view = lambda *arg: 'OK' + class Foo: + pass + config = self._makeOne() + config.add_view(context=Foo, view=view) + foo = implementedBy(Foo) + wrapper = self._getViewCallable(config, foo) + self.assertEqual(wrapper, view) + + def test_add_view_context_as_iface(self): + view = lambda *arg: 'OK' + config = self._makeOne() + config.add_view(context=IDummy, view=view) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + def test_add_view_for_as_class(self): + # ``for_`` is older spelling for ``context`` from zope.interface import implementedBy view = lambda *arg: 'OK' class Foo: @@ -504,12 +523,23 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(wrapper, view) def test_add_view_for_as_iface(self): + # ``for_`` is older spelling for ``context`` view = lambda *arg: 'OK' config = self._makeOne() config.add_view(for_=IDummy, view=view) wrapper = self._getViewCallable(config, IDummy) self.assertEqual(wrapper, view) + def test_add_view_context_trumps_for(self): + # ``for_`` is older spelling for ``context`` + view = lambda *arg: 'OK' + config = self._makeOne() + class Foo: + pass + config.add_view(context=IDummy, for_=Foo, view=view) + wrapper = self._getViewCallable(config, IDummy) + self.assertEqual(wrapper, view) + def test_add_view_register_secured_view(self): from zope.interface import Interface from repoze.bfg.interfaces import IRequest @@ -1091,6 +1121,17 @@ class ConfiguratorTests(unittest.TestCase): self.assertEqual(wrapper(None, None), 'OK') self._assertRoute(config, 'name', 'path') + def test_add_route_with_view_context(self): + config = self._makeOne() + view = lambda *arg: 'OK' + config.add_route('name', 'path', view=view, view_context=IDummy) + request_type = self._getRouteRequestIface(config, 'name') + wrapper = self._getViewCallable(config, IDummy, request_type) + self.assertEqual(wrapper(None, None), 'OK') + self._assertRoute(config, 'name', 'path') + wrapper = self._getViewCallable(config, IOther, request_type) + self.assertEqual(wrapper, None) + def test_add_route_with_view_for(self): config = self._makeOne() view = lambda *arg: 'OK' @@ -1102,7 +1143,7 @@ class ConfiguratorTests(unittest.TestCase): wrapper = self._getViewCallable(config, IOther, request_type) self.assertEqual(wrapper, None) - def test_add_route_with_view_for_alias(self): + def test_add_route_with_for_(self): config = self._makeOne() view = lambda *arg: 'OK' config.add_route('name', 'path', view=view, for_=IDummy) diff --git a/repoze/bfg/tests/test_view.py b/repoze/bfg/tests/test_view.py index 677c15bc8..94b896893 100644 --- a/repoze/bfg/tests/test_view.py +++ b/repoze/bfg/tests/test_view.py @@ -289,7 +289,7 @@ class TestBFGViewDecorator(unittest.TestCase): decorator = self._makeOne() self.assertEqual(decorator.name, '') self.assertEqual(decorator.request_type, None) - self.assertEqual(decorator.for_, None) + self.assertEqual(decorator.context, None) self.assertEqual(decorator.permission, None) def test_create_nondefaults(self): @@ -297,7 +297,7 @@ class TestBFGViewDecorator(unittest.TestCase): permission='foo') self.assertEqual(decorator.name, None) self.assertEqual(decorator.request_type, None) - self.assertEqual(decorator.for_, None) + self.assertEqual(decorator.context, None) self.assertEqual(decorator.permission, 'foo') def test_call_function(self): @@ -308,7 +308,7 @@ class TestBFGViewDecorator(unittest.TestCase): self.failUnless(wrapped is foo) settings = wrapped.__bfg_view_settings__[0] self.assertEqual(settings['permission'], None) - self.assertEqual(settings['for_'], None) + self.assertEqual(settings['context'], None) self.assertEqual(settings['request_type'], None) def test_call_oldstyle_class(self): @@ -319,7 +319,7 @@ class TestBFGViewDecorator(unittest.TestCase): self.failUnless(wrapped is foo) settings = wrapped.__bfg_view_settings__[0] self.assertEqual(settings['permission'], None) - self.assertEqual(settings['for_'], None) + self.assertEqual(settings['context'], None) self.assertEqual(settings['request_type'], None) def test_call_newstyle_class(self): @@ -330,7 +330,7 @@ class TestBFGViewDecorator(unittest.TestCase): self.failUnless(wrapped is foo) settings = wrapped.__bfg_view_settings__[0] self.assertEqual(settings['permission'], None) - self.assertEqual(settings['for_'], None) + self.assertEqual(settings['context'], None) self.assertEqual(settings['request_type'], None) def test_stacking(self): diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index b50f841c2..3cbeb05c8 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -117,6 +117,27 @@ class TestViewDirective(unittest.TestCase): regview = reg.adapters.lookup((IDummy, IRequest), IView, name='') self.assertEqual(regview(None, None), 'OK') + def test_context_trumps_for(self): + from repoze.bfg.threadlocal import get_current_registry + from repoze.bfg.interfaces import IView + from repoze.bfg.interfaces import IRequest + context = DummyContext() + reg = get_current_registry() + view = lambda *arg: 'OK' + class Foo: + pass + self._callFUT(context, 'repoze.view', for_=Foo, view=view, + context=IDummy) + actions = context.actions + self.assertEqual(len(actions), 1) + discrim = ('view', IDummy, '', None, IView, None, None, None, None, + None, False, None, None, None) + self.assertEqual(actions[0]['discriminator'], discrim) + register = actions[0]['callable'] + register() + regview = reg.adapters.lookup((IDummy, IRequest), IView, name='') + self.assertEqual(regview(None, None), 'OK') + class TestNotFoundDirective(unittest.TestCase): def setUp(self): testing.setUp() @@ -475,6 +496,63 @@ class TestRouteDirective(unittest.TestCase): wrapped = reg.adapters.lookup((Interface, request_type), IView, name='') self.failUnless(wrapped) + def test_with_view_and_view_context(self): + from repoze.bfg.threadlocal import get_current_registry + from repoze.bfg.interfaces import IView + from repoze.bfg.interfaces import IRouteRequest + context = DummyContext() + view = lambda *arg: 'OK' + self._callFUT(context, 'name', 'path', view=view, view_context=IDummy) + actions = context.actions + self.assertEqual(len(actions), 2) + + route_action = actions[0] + route_action['callable']() + route_discriminator = route_action['discriminator'] + self.assertEqual(route_discriminator, + ('route', 'name', False, None, None, None, None,None)) + self._assertRoute('name', 'path') + + view_action = actions[1] + reg = get_current_registry() + request_type = reg.getUtility(IRouteRequest, 'name') + view_discriminator = view_action['discriminator'] + discrim = ('view', IDummy, '', request_type, IView, None, None, None, + 'name', None, False, None, None, None) + self.assertEqual(view_discriminator, discrim) + wrapped = reg.adapters.lookup((IDummy, request_type), IView, name='') + self.failUnless(wrapped) + + def test_with_view_context_trumps_view_for(self): + from repoze.bfg.threadlocal import get_current_registry + from repoze.bfg.interfaces import IView + from repoze.bfg.interfaces import IRouteRequest + context = DummyContext() + view = lambda *arg: 'OK' + class Foo: + pass + self._callFUT(context, 'name', 'path', view=view, view_context=IDummy, + view_for=Foo) + actions = context.actions + self.assertEqual(len(actions), 2) + + route_action = actions[0] + route_action['callable']() + route_discriminator = route_action['discriminator'] + self.assertEqual(route_discriminator, + ('route', 'name', False, None, None, None, None,None)) + self._assertRoute('name', 'path') + + view_action = actions[1] + reg = get_current_registry() + request_type = reg.getUtility(IRouteRequest, 'name') + view_discriminator = view_action['discriminator'] + discrim = ('view', IDummy, '', request_type, IView, None, None, None, + 'name', None, False, None, None, None) + self.assertEqual(view_discriminator, discrim) + wrapped = reg.adapters.lookup((IDummy, request_type), IView, name='') + self.failUnless(wrapped) + def test_with_dotted_renderer(self): from repoze.bfg.threadlocal import get_current_registry diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py index 8a33e246d..af3acb8b6 100644 --- a/repoze/bfg/view.py +++ b/repoze/bfg/view.py @@ -233,7 +233,7 @@ class bfg_view(object): from models import MyModel - @bfg_view(name='my_view', for_=MyModel, permission='read', + @bfg_view(name='my_view', context=MyModel, permission='read', route_name='site1') def my_view(context, request): return 'OK' @@ -243,7 +243,7 @@ class bfg_view(object): import views import models - config.add_view(views.my_view, for_=models.MyModel, name='my_view', + config.add_view(views.my_view, context=models.MyModel, name='my_view', permission='read', 'route_name='site1') Or might replace the following ZCML ``view`` declaration:: @@ -257,13 +257,14 @@ class bfg_view(object): /> The following arguments are supported as arguments to - ``bfg_view``: ``for_``, ``permission``, ``name``, + ``bfg_view``: ``context``, ``permission``, ``name``, ``request_type``, ``route_name``, ``request_method``, ``request_param``, ``containment``, ``xhr``, ``accept``, ``header`` and ``path_info``. - If ``for_`` is not supplied, the interface - ``zope.interface.Interface`` (matching any context) is used. + If ``context`` is not supplied, the interface + ``zope.interface.Interface`` (matching any context) is used. An alias + for ``context`` is ``for_``. If ``permission`` is not supplied, no permission is registered for this view (it's accessible by any caller). @@ -456,10 +457,10 @@ class bfg_view(object): route_name=None, request_method=None, request_param=None, containment=None, attr=None, renderer=None, wrapper=None, xhr=False, accept=None, header=None, path_info=None, - custom_predicates=()): + custom_predicates=(), context=None): self.name = name self.request_type = request_type - self.for_ = for_ + self.context = context or for_ self.permission = permission self.route_name = route_name self.request_method = request_method diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index 6467907db..c09a52fcd 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -37,11 +37,17 @@ from repoze.bfg.threadlocal import get_current_registry ###################### directives ########################## class IViewDirective(Interface): - for_ = GlobalObject( + context = GlobalObject( title=u"The interface or class this view is for.", required=False ) + for_ = GlobalObject( + title=(u"The interface or class this view is for (alternate spelling " + "of ``context``)."), + required=False + ) + permission = TextLine( title=u"Permission", description=u"The permission needed to use the view.", @@ -162,6 +168,7 @@ def view( header=None, path_info=None, custom_predicates=(), + context=None, cacheable=True, # not used, here for b/w compat < 0.8 ): @@ -178,10 +185,12 @@ def view( if renderer and '.' in renderer: renderer = path_spec(_context, renderer) + context = context or for_ + def register(): config = Configurator(reg, package=_context.package) config.add_view( - permission=permission, for_=for_, view=view, name=name, + permission=permission, context=context, view=view, name=name, request_type=request_type, route_name=route_name, request_method=request_method, request_param=request_param, containment=containment, attr=attr, renderer=renderer, @@ -189,7 +198,7 @@ def view( path_info=path_info, custom_predicates=custom_predicates, _info=_context.info) - discriminator = ['view', for_, name, request_type, IView, containment, + discriminator = ['view', context, name, request_type, IView, containment, request_param, request_method, route_name, attr, xhr, accept, header, path_info] @@ -211,9 +220,10 @@ class IRouteDirective(Interface): factory = GlobalObject(title=u'context factory', required=False) view = GlobalObject(title=u'view', required=False) - view_for = GlobalObject(title=u'view_for', required=False) - # alias for view_for + view_context = GlobalObject(title=u'view_context', required=False) + # aliases for view_context for_ = GlobalObject(title=u'for', required=False) + view_for = GlobalObject(title=u'view_for', required=False) view_permission = TextLine(title=u'view_permission', required=False) # alias for view_permission @@ -255,7 +265,7 @@ def route(_context, name, path, view=None, view_for=None, view_request_param=None, view_containment=None, view_attr=None, renderer=None, view_renderer=None, view_header=None, view_accept=None, view_xhr=False, - view_path_info=None): + view_path_info=None, view_context=None): """ Handle ``route`` ZCML directives """ # the strange ordering of the request kw args above is for b/w @@ -264,7 +274,9 @@ def route(_context, name, path, view=None, view_for=None, # in the routelist will be tried reg = get_current_registry() - view_for = view_for or for_ + if view_context is None: + view_context = view_for or for_ + view_permission = view_permission or permission view_renderer = view_renderer or renderer if view_renderer and '.' in view_renderer: @@ -284,7 +296,7 @@ def route(_context, name, path, view=None, view_for=None, request_param=request_param, custom_predicates=custom_predicates, view=view, - view_for=view_for, + view_context=view_context, view_permission=view_permission, view_request_method=view_request_method, view_request_param=view_request_param, @@ -315,7 +327,7 @@ def route(_context, name, path, view=None, view_for=None, reg.registerUtility(request_iface, IRouteRequest, name=name) _context.action( discriminator = ( - 'view', view_for, '', request_iface, IView, + 'view', view_context, '', request_iface, IView, view_containment, view_request_param, view_request_method, name, view_attr, view_xhr, view_accept, view_header, view_path_info), -- cgit v1.2.3