diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-01-16 18:58:16 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-01-16 18:58:16 +0000 |
| commit | 5a7f9a4d57424f14a1e072cc06b6bf7a191a7d08 (patch) | |
| tree | b44448198ddf8031b3e09b83dd731f2ae1d6623a /repoze/bfg/view.py | |
| parent | 4856cc54bcd5feb97db49f1cca923afb01c0bf02 (diff) | |
| download | pyramid-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.py | 89 |
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 + |
