summaryrefslogtreecommitdiff
path: root/repoze/bfg/zcml.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-06-18 21:49:33 +0000
committerChris McDonough <chrism@agendaless.com>2009-06-18 21:49:33 +0000
commitf5c25ef97393f7b4bf1353b11eeb841c53e2feaf (patch)
tree7c820aaa1a769dfc096aed05c50116821e89707a /repoze/bfg/zcml.py
parent7687344b77fbc9c4bf998d20828b10a339b90eed (diff)
downloadpyramid-f5c25ef97393f7b4bf1353b11eeb841c53e2feaf.tar.gz
pyramid-f5c25ef97393f7b4bf1353b11eeb841c53e2feaf.tar.bz2
pyramid-f5c25ef97393f7b4bf1353b11eeb841c53e2feaf.zip
- Allow views to be *optionally* defined as callables that accept only
a request object, instead of both a context and a request (which still works, and always will). The following types work as views in this style: - functions that accept a single argument ``request``, e.g.:: def aview(request): pass - new and old-style classes that have an ``__init__`` method that accepts ``self, request``, e.g.:: def View(object): __init__(self, request): pass - Arbitrary callables that have a ``__call__`` method that accepts ``self, request``, e.g.:: def AView(object): def __call__(self, request): pass view = AView() This likely should have been the calling convention all along, as the request has ``context`` as an attribute already, and with views called as a result of URL dispatch, having the context in the arguments is not very useful. C'est la vie.
Diffstat (limited to 'repoze/bfg/zcml.py')
-rw-r--r--repoze/bfg/zcml.py75
1 files changed, 66 insertions, 9 deletions
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index eeb8dfc32..80f8f1f38 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -64,6 +64,8 @@ def view(
else:
request_type = _context.resolve(request_type)
+ derived_view = view
+
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,
@@ -71,14 +73,29 @@ def view(
# position arguments, then immediately invoke the __call__
# method of the instance with no arguments; __call__ should
# return an IResponse).
- _view = view
- def _bfg_class_view(context, request):
- inst = _view(context, request)
- return inst()
- _bfg_class_view.__module__ = view.__module__
- _bfg_class_view.__name__ = view.__name__
- _bfg_class_view.__doc__ = view.__doc__
- view = _bfg_class_view
+ if requestonly(view):
+ def _bfg_class_requestonly_view(context, request):
+ inst = view(request)
+ return inst()
+ derived_view = _bfg_class_requestonly_view
+ else:
+ def _bfg_class_view(context, request):
+ inst = view(context, request)
+ return inst()
+ derived_view = _bfg_class_view
+
+ elif requestonly(view):
+ def _bfg_requestonly_view(context, request):
+ return view(request)
+ derived_view = _bfg_requestonly_view
+
+ if derived_view is not view:
+ derived_view.__module__ = view.__module__
+ derived_view.__doc__ = view.__doc__
+ try:
+ derived_view.__name__ = view.__name__
+ except AttributeError:
+ derived_view.__name__ = repr(view)
if permission:
pfactory = ViewPermissionFactory(permission)
@@ -95,7 +112,7 @@ def view(
discriminator = ('view', for_, name, request_type, IView),
callable = handler,
args = ('registerAdapter',
- view, (for_, request_type), IView, name, _context.info),
+ derived_view, (for_, request_type), IView, name, _context.info),
)
class IViewDirective(Interface):
@@ -338,3 +355,43 @@ class Uncacheable(object):
""" Include in discriminators of actions which are not cacheable;
this class only exists for backwards compatibility (<0.8.1)"""
+def requestonly(class_or_callable):
+ """ Return true of the class or callable accepts only a request argument,
+ as opposed to something that accepts context, request """
+ 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 = class_or_callable.__call__
+ 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