summaryrefslogtreecommitdiff
path: root/repoze/bfg/view.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-01-16 18:58:16 +0000
committerChris McDonough <chrism@agendaless.com>2009-01-16 18:58:16 +0000
commit5a7f9a4d57424f14a1e072cc06b6bf7a191a7d08 (patch)
treeb44448198ddf8031b3e09b83dd731f2ae1d6623a /repoze/bfg/view.py
parent4856cc54bcd5feb97db49f1cca923afb01c0bf02 (diff)
downloadpyramid-5a7f9a4d57424f14a1e072cc06b6bf7a191a7d08.tar.gz
pyramid-5a7f9a4d57424f14a1e072cc06b6bf7a191a7d08.tar.bz2
pyramid-5a7f9a4d57424f14a1e072cc06b6bf7a191a7d08.zip
Features
-------- - The functionality of ``repoze.bfg.convention`` has been merged into the core. Applications which make use of ``repoze.bfg.convention`` will continue to work indefinitely, but it is recommended that apps stop depending upon it. To do so, substitute imports of ``repoze.bfg.convention.bfg_view`` with imports of ``repoze.bfg.view.bfg_view``, and change the stanza in ZCML from ``<convention package=".">`` to ``<grok package=".">``. As a result of the merge, bfg has grown a new dependency: ``martian``. - View functions which use the pushpage decorator are now pickleable (meaning their use won't prevent a ``configure.zcml.cache`` file from being written to disk). Implementation Changes ---------------------- - The ``wsgiapp`` decorator now uses ``webob.Request.get_response`` to do its work rather than relying on howgrown WSGI code.
Diffstat (limited to 'repoze/bfg/view.py')
-rw-r--r--repoze/bfg/view.py89
1 files changed, 89 insertions, 0 deletions
diff --git a/repoze/bfg/view.py b/repoze/bfg/view.py
index 3f9216b0d..f580a4fb1 100644
--- a/repoze/bfg/view.py
+++ b/repoze/bfg/view.py
@@ -12,6 +12,10 @@ from repoze.bfg.interfaces import IView
from repoze.bfg.security import Unauthorized
from repoze.bfg.security import Allowed
+from zope.interface import Interface
+
+from repoze.bfg.interfaces import IRequest
+
_marker = ()
def view_execution_permitted(context, request, name=''):
@@ -162,3 +166,88 @@ class static(object):
response.headerlist = headers
return response
+class bfg_view(object):
+ """ Decorator which allows Python code to make view registrations
+ instead of using ZCML for the same purpose.
+
+ E.g. in the module ``views.py``::
+
+ from models import IMyModel
+ from repoze.bfg.interfaces import IRequest
+
+ @bfg_view(name='my_view', request_type=IRequest, for_=IMyModel,
+ permission='read'))
+ def my_view(context, request):
+ return render_template_to_response('templates/my.pt')
+
+ Equates to the ZCML::
+
+ <bfg:view
+ for='.models.IMyModel'
+ view='.views.my_view'
+ name='my_view'
+ permission='read'
+ />
+
+ If ``name`` is not supplied, the empty string is used (implying
+ the default view).
+
+ If ``request_type`` is not supplied, the interface
+ ``repoze.bfg.interfaces.IRequest`` is used.
+
+ If ``for_`` is not supplied, the interface
+ ``zope.interface.Interface`` (implying *all* interfaces) is used.
+
+ If ``permission`` is not supplied, no permission is registered for
+ this view (it's accessible by any caller).
+
+ Any individual or all parameters can be omitted. The simplest
+ bfg_view declaration then becomes::
+
+ @bfg_view()
+ def my_view(...):
+ ...
+
+ Such a registration implies that the view name will be
+ ``my_view``, registered for models with the
+ ``zope.interface.Interface`` interface, using no permission,
+ 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::
+
+ <grok package="."/>
+ """
+ def __init__(self, name='', request_type=IRequest, for_=Interface,
+ permission=None):
+ self.name = name
+ self.request_type = request_type
+ self.for_ = for_
+ self.permission = permission
+
+ def __call__(self, wrapped):
+ # We intentionally return a do-little un-functools-wrapped
+ # decorator here so as to make the decorated function
+ # unpickleable; applications which use bfg_view decorators
+ # should never be able to load actions from an actions cache;
+ # instead they should rerun the file_configure function each
+ # time the application starts in case any of the decorators
+ # has been changed. Disallowing these functions from being
+ # pickled enforces that.
+ def decorator(context, request):
+ return wrapped(context, request)
+ decorator.__is_bfg_view__ = True
+ decorator.__permission__ = self.permission
+ decorator.__for__ = self.for_
+ decorator.__view_name__ = self.name
+ decorator.__request_type__ = self.request_type
+ # we assign to __grok_module__ here rather than __module__ to
+ # make it unpickleable but allow for the grokker to be able to
+ # find it
+ decorator.__grok_module__ = wrapped.__module__
+ decorator.__name__ = wrapped.__name__
+ decorator.__doc__ = wrapped.__doc__
+ decorator.__dict__.update(wrapped.__dict__)
+ return decorator
+