diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-10-18 05:50:54 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-10-18 05:50:54 +0000 |
| commit | 1dc3907e59995852d5ee0251c1c92a360f03ed35 (patch) | |
| tree | 38da7879503f2b55b995cee89a2aebe6c7d6f076 /repoze/bfg/zcml.py | |
| parent | 2cce431f02a37c119eacfc3dfa94af9fe3305de1 (diff) | |
| download | pyramid-1dc3907e59995852d5ee0251c1c92a360f03ed35.tar.gz pyramid-1dc3907e59995852d5ee0251c1c92a360f03ed35.tar.bz2 pyramid-1dc3907e59995852d5ee0251c1c92a360f03ed35.zip | |
- The ``@bfg_view`` decorator can now be used against a class method::
from webob import Response
from repoze.bfg.view import bfg_view
class MyView(object):
def __init__(self, context, request):
self.context = context
self.request = request
@bfg_view(name='hello')
def amethod(self):
return Response('hello from %s!' % self.context)
When the bfg_view decorator is used against a class method, a view
is registered for the *class* (it's a "class view" where the "attr"
happens to be the method they're attached to), so the view class
must have a suitable constructor.
Diffstat (limited to 'repoze/bfg/zcml.py')
| -rw-r--r-- | repoze/bfg/zcml.py | 62 |
1 files changed, 37 insertions, 25 deletions
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index 681c4da1e..cbe438560 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -1,6 +1,8 @@ +import inspect import re import sys +from zope.interface import implements from zope.component import getSiteManager from zope.component import getUtility from zope.component import queryUtility @@ -17,6 +19,7 @@ from zope.schema import Int from zope.schema import TextLine import martian +import martian.interfaces from repoze.bfg.interfaces import IAuthenticationPolicy from repoze.bfg.interfaces import IAuthorizationPolicy @@ -675,47 +678,56 @@ def scan(_context, package, martian=martian): # martian overrideable only for unit tests multi_grokker = BFGMultiGrokker() multi_grokker.register(BFGViewGrokker()) + multi_grokker.register(BFGClassGrokker()) module_grokker = martian.ModuleGrokker(grokker=multi_grokker) martian.grok_dotted_name(package.__name__, grokker=module_grokker, context=_context, exclude_filter=exclude) ################# utility stuff #################### -class BFGViewMarker(object): +class Class(object): + pass + +class AnythingButAClass(object): pass class BFGMultiGrokker(martian.core.MultiInstanceOrClassGrokkerBase): def get_bases(self, obj): - if hasattr(obj, '__bfg_view_settings__'): - return [BFGViewMarker] + if inspect.isclass(obj): + return [Class] + elif hasattr(obj, '__bfg_view_settings__'): + return [AnythingButAClass] return [] +class BFGClassGrokker(object): + implements(martian.interfaces.IGrokker) + martian = martian # for unit tests + martian.component(Class) + def grok(self, name, class_, module_info=None, **kw): + # The class itself may be decorated, so we feed it to BFGViewGrokker + found = BFGViewGrokker().grok(name, class_, **kw) + + # grok any decorations attached to the class' method (direct + # methods only, not methods of any base class) + methods = inspect.getmembers(class_, inspect.ismethod) + basemethods = class_.__dict__.keys() + for method_name, method in methods: + if method_name in basemethods: + # it's not an inherited method + config = getattr(method, '__bfg_view_settings__', []) + for settings in config: + settings = dict(settings) + settings['attr'] = settings['attr'] or method_name + view(kw['context'], view=class_, **settings) + found = True + return found + class BFGViewGrokker(martian.InstanceGrokker): - martian.component(BFGViewMarker) + martian.component(AnythingButAClass) def grok(self, name, obj, **kw): config = getattr(obj, '__bfg_view_settings__', []) for settings in config: - permission = settings['permission'] - for_ = settings['for_'] - name = settings['name'] - request_type = settings['request_type'] - route_name = settings['route_name'] - request_method = settings['request_method'] - request_param = settings['request_param'] - containment = settings['containment'] - wrapper = settings['wrapper_viewname'] - attr = settings['attr'] - renderer = settings['renderer'] - xhr = settings['xhr'] - accept = settings['accept'] - header = settings['header'] - context = kw['context'] - view(context, permission=permission, for_=for_, - view=obj, name=name, request_type=request_type, - route_name=route_name, request_method=request_method, - request_param=request_param, containment=containment, - attr=attr, renderer=renderer, wrapper=wrapper, - xhr=xhr, accept=accept, header=header) + view(kw['context'], view=obj, **settings) return bool(config) def exclude(name): |
