summaryrefslogtreecommitdiff
path: root/repoze/bfg/view.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-05-21 16:01:58 +0000
committerChris McDonough <chrism@agendaless.com>2009-05-21 16:01:58 +0000
commit5a11e2ad0828b7c763d0c81211f686a85bc0324c (patch)
tree750deaa5086279a1cd0baa28c0d5bdaa17414463 /repoze/bfg/view.py
parent385084582eeff5f2f1a93f3b90c091dc1a4ad50e (diff)
downloadpyramid-5a11e2ad0828b7c763d0c81211f686a85bc0324c.tar.gz
pyramid-5a11e2ad0828b7c763d0c81211f686a85bc0324c.tar.bz2
pyramid-5a11e2ad0828b7c763d0c81211f686a85bc0324c.zip
- Class objects may now be used as view callables (both via ZCML and
via use of the ``bfg_view`` decorator in Python 2.6 as a class decorator). The calling semantics when using a class as a view callable is similar to that of using a class as a Zope "browser view": the class' ``__init__`` must accept two positional parameters (conventionally named ``context``, and ``request``). The resulting instance must be callable (it must have a ``__call__`` method). When called, the instance should return a response. For example:: from webob import Response class MyView(object): def __init__(self, context, request): self.context = context self.request = request def __call__(self): return Response('hello from %s!' % self.context) See the "Views" chapter in the documentation and the ``repoze.bfg.view`` API documentation for more information.
Diffstat (limited to 'repoze/bfg/view.py')
-rw-r--r--repoze/bfg/view.py59
1 files changed, 49 insertions, 10 deletions
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index a9a7cb973..a867987a5 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -1,3 +1,5 @@
+import inspect
+
from paste.urlparser import StaticURLParser
from zope.component import queryMultiAdapter
from zope.component import queryUtility
@@ -175,8 +177,8 @@ class static(object):
return request_copy.get_response(self.app)
class bfg_view(object):
- """ Decorator which allows Python code to make view registrations
- instead of using ZCML for the same purpose.
+ """ Function or class decorator which allows Python code to make
+ view registrations instead of using ZCML for the same purpose.
E.g. in the module ``views.py``::
@@ -222,8 +224,36 @@ class bfg_view(object):
registered against requests which implement the default IRequest
interface.
- To make use of bfg_view declarations, insert the following
- boilerplate into your application registry's ZCML::
+ The ``bfg_view`` decorator can also be used as a class decorator
+ in Python 2.6 and better (Python 2.5 and below do not support
+ class decorators)::
+
+ from webob import Response
+ from repoze.bfg.view import bfg_view
+
+ @bfg_view()
+ class MyView(object):
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+ def __call__(self):
+ return Response('hello from %s!' % self.context)
+
+ .. warning:: This feature is new in 0.8.1.
+
+ .. note:: When a view is a class, the calling semantics are
+ different than when it is a function or another
+ non-class callable. When a view is a class, the class'
+ ``__init__`` is called with the context and the request
+ parameters, creating an instance. Subsequently that
+ instance's ``__call__`` method is invoked with no
+ parameters. The class' ``__call__`` method must return a
+ response. This provides behavior similar to a Zope
+ 'browser view' (Zope 'browser views' are typically classes
+ instead of simple callables).
+
+ To make use of any bfg_view declaration, you *must* insert the
+ following boilerplate into your application registry's ZCML::
<scan package="."/>
"""
@@ -235,16 +265,25 @@ class bfg_view(object):
self.permission = permission
def __call__(self, wrapped):
- def _bfg_view(context, request):
- return wrapped(context, request)
+ _bfg_view = wrapped
+ if inspect.isclass(_bfg_view):
+ # If the object we're decorating 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).
+ def _bfg_class_view(context, request):
+ inst = wrapped(context, request)
+ return inst()
+ _bfg_class_view.__module__ = wrapped.__module__
+ _bfg_class_view.__name__ = wrapped.__name__
+ _bfg_class_view.__doc__ = wrapped.__doc__
+ _bfg_view = _bfg_class_view
_bfg_view.__is_bfg_view__ = True
_bfg_view.__permission__ = self.permission
_bfg_view.__for__ = self.for_
_bfg_view.__view_name__ = self.name
_bfg_view.__request_type__ = self.request_type
- _bfg_view.__module__ = wrapped.__module__
- _bfg_view.__name__ = wrapped.__name__
- _bfg_view.__doc__ = wrapped.__doc__
- _bfg_view.__dict__.update(wrapped.__dict__)
return _bfg_view