summaryrefslogtreecommitdiff
path: root/repoze/bfg/view.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-09-14 04:33:38 +0000
committerChris McDonough <chrism@agendaless.com>2009-09-14 04:33:38 +0000
commit04e182bbc0c077afcd921f0df4231020549dc217 (patch)
treea994d2508aaac376b76e04dd4335129b6391dca1 /repoze/bfg/view.py
parentf587c76deac60c0a328975dcc4641d0f85984e63 (diff)
downloadpyramid-04e182bbc0c077afcd921f0df4231020549dc217.tar.gz
pyramid-04e182bbc0c077afcd921f0df4231020549dc217.tar.bz2
pyramid-04e182bbc0c077afcd921f0df4231020549dc217.zip
- A ZCML ``view`` directive (and the associated ``bfg_view``
decorator) can now accept an "attr" value. If an "attr" value is supplied, it is considered a method named of the view object to be called when the response is required. This is typically only good for views that are classes or instances (not so useful for functions, as functions typically have no methods other than ``__call__``). - A ZCML ``view`` directive (and the associated ``bfg_view`` decorator) can now accept a "template" value. If a "template" value is supplied, and the view callable returns a dictionary, the associated template is rendered with the dictionary as keyword arguments.
Diffstat (limited to 'repoze/bfg/view.py')
-rw-r--r--repoze/bfg/view.py106
1 files changed, 96 insertions, 10 deletions
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 8e6d1c7fe..794c7fa65 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -33,6 +33,9 @@ from repoze.bfg.path import caller_package
from repoze.bfg.static import PackageURLParser
+from repoze.bfg.templating import renderer_from_path
+from repoze.bfg.templating import _auto_reload
+
deprecated('view_execution_permitted',
"('from repoze.bfg.view import view_execution_permitted' was "
"deprecated as of repoze.bfg 1.0; instead use 'from "
@@ -229,6 +232,13 @@ class bfg_view(object):
If ``name`` is not supplied, the empty string is used (implying
the default view name).
+ If ``attr`` is not supplied, ``None`` is used (implying the
+ function itself if the view is a function, or the ``__call__``
+ callable attribute if the view is a class).
+
+ If ``template`` is not supplied, ``None`` is used (meaning that no
+ template is associated with this view).
+
If ``request_type`` is not supplied, the interface
``repoze.bfg.interfaces.IRequest`` is used, implying the standard
request interface type.
@@ -322,7 +332,7 @@ class bfg_view(object):
"""
def __init__(self, name='', request_type=None, for_=None, permission=None,
route_name=None, request_method=None, request_param=None,
- containment=None):
+ containment=None, attr=None, template=None):
self.name = name
self.request_type = request_type
self.for_ = for_
@@ -331,9 +341,11 @@ class bfg_view(object):
self.request_method = request_method
self.request_param = request_param
self.containment = containment
+ self.attr = attr
+ self.template = template
def __call__(self, wrapped):
- _bfg_view = map_view(wrapped)
+ _bfg_view = map_view(wrapped, self.attr, self.template)
_bfg_view.__is_bfg_view__ = True
_bfg_view.__permission__ = self.permission
_bfg_view.__for__ = self.for_
@@ -413,8 +425,41 @@ class MultiView(object):
continue
raise NotFound(self.name)
-def map_view(view):
+def templated_response(template_name, response, view, context, request,
+ auto_reload=False):
+ if is_response(response):
+ return response
+ renderer = renderer_from_path(template_name, auto_reload=auto_reload)
+ kw = {'view':view, 'template_name':template_name, 'context':context,
+ 'request':request}
+ try:
+ kw.update(response)
+ except TypeError:
+ return response
+ result = renderer(**kw)
+ response_factory = queryUtility(IResponseFactory, default=Response)
+ response = response_factory(result)
+ content_type = kw.get('content_type_', None)
+ if content_type is not None:
+ response.content_type = content_type
+ headerlist = kw.get('headerlist_', None)
+ if headerlist is not None:
+ for k, v in headerlist:
+ response.headers.add(k, v)
+ status = kw.get('status_', None)
+ if status is not None:
+ response.status = status
+ charset = kw.get('charset_', None)
+ if charset is not None:
+ response.charset = charset
+ cache_for = kw.get('cache_for_', None)
+ if cache_for is not None:
+ response.cache_expires = cache_for
+ return response
+
+def map_view(view, attr=None, template=None):
wrapped_view = view
+ auto_reload = _auto_reload()
if inspect.isclass(view):
# If the object we've located is a class, turn it into a
@@ -423,33 +468,74 @@ def map_view(view):
# position arguments, then immediately invoke the __call__
# method of the instance with no arguments; __call__ should
# return an IResponse).
- if requestonly(view):
+ if requestonly(view, attr):
# its __init__ accepts only a single request argument,
# instead of both context and request
def _bfg_class_requestonly_view(context, request):
inst = view(request)
- return inst()
+ if attr is None:
+ response = inst()
+ else:
+ response = getattr(inst, attr)()
+ if template:
+ response = templated_response(template, response, inst,
+ context, request, auto_reload)
+ return response
wrapped_view = _bfg_class_requestonly_view
else:
# its __init__ accepts both context and request
def _bfg_class_view(context, request):
inst = view(context, request)
- return inst()
+ if attr is None:
+ response = inst()
+ else:
+ response = getattr(inst, attr)()
+ if template:
+ response = templated_response(template, response, inst,
+ context, request, auto_reload)
+ return response
wrapped_view = _bfg_class_view
- elif requestonly(view):
+ elif requestonly(view, attr):
# its __call__ accepts only a single request argument,
# instead of both context and request
def _bfg_requestonly_view(context, request):
- return view(request)
+ if attr is None:
+ response = view(request)
+ else:
+ response = getattr(view, attr)(request)
+
+ if template:
+ response = templated_response(template, response, view,
+ context, request, auto_reload)
+ return response
wrapped_view = _bfg_requestonly_view
+ elif attr:
+ def _bfg_attr_view(context, request):
+ response = getattr(view, attr)(context, request)
+ if template:
+ response = templated_response(template, response, view,
+ context, request, auto_reload)
+ return response
+ wrapped_view = _bfg_attr_view
+
+ elif template:
+ def _templated_view(context, request):
+ response = view(context, request)
+ response = templated_response(template, response, view,
+ context, request, auto_reload)
+ return response
+ wrapped_view = _templated_view
+
decorate_view(wrapped_view, view)
return wrapped_view
-def requestonly(class_or_callable):
+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):
@@ -459,7 +545,7 @@ def requestonly(class_or_callable):
return False
else:
try:
- fn = class_or_callable.__call__
+ fn = getattr(class_or_callable, attr)
except AttributeError:
return False