There is no simple way to evaluate repoze.what predicates such as has_permission() inside the controller or inside a template. Such a feature would be useful for changing the behavior or displaying additional information in the template depending on the permissions, a very common requirement.
We already have related tickets #2172 and #2173, but #2172 does only cover one special case (and is not yet implemented) and #2173 is not simple enough.
There is a thread on turbogears-trunk summing up the discussion and proposing different solutions for this problem. Unfortunately, there was not enough feedback yet to make a good decision which of the ideas should get implemented. Maybe there is also a better solution or a modifications of these ideas will do.
I think this is an important feature that should get into TG 2.0, so I've given this ticket a high priority. I's actually easy to implement, but we need to make an API decision here. Any comments on this ticket or on the thread mentioned above are highly appreciated.
The two ideas from that thread that need further discussion were numbers 3) and 4) which I will repeat here:
3) Using the standard boolean evaluation mechanism
Michael came up with the idea to overwrite the __nonzero__ method of predicates (side note, __nonzero__ is for boolean evaluation and thus was renamed to __bool__ in Python 3.0).
This method could for example raise an error when used in the form py:if="has_permission('manage')" without the evaluate call (as proposed in #2173). But we could also go a step further and let __nonzero__ automatically evaluate the predicate. The predicates would have a dual use then, both for require decorators (not immediately evaluated) and for py:if statements
(immediately evaluated).
The following simple monkey-patch would allow this double usage of all repoze.what predicates in TG2:
from tg import request
from repoze.what.predicates import Predicate
Predicate.__nonzero__ = lambda self: self.is_met(request.environ)
Instead, we could also create a TG specific subclass of repoze.what predicates that allows this double usage, and also create copies of the existing predicates on the fly.
Both the monkey-patching (or subclassing and copying) and the double usage may appear a bit hackish and magical though. But I think it's pretty elegant and straightforward and the following idea works a bit magical, too.
4) Providing a special "access" object
A different solution is to add an access object to TG2 and make it a standard template variable that auto-evaluates predicates passed as attributes. Here is a possible implementation:
from tg import request
from repoze.what import predicates
class Access(object):
"""Environ-aware predicates evaluating immediately."""
def __getattr__(self, name):
predicate = getattr(predicates, name)
if callable(predicate):
def predicate_is_met(*args, **kwargs):
return predicate(*args, *kwargs).is_met(
request.environ)
return predicate_is_met
else:
return predicate
access = Access() # make this a standard tg template variable
This would allow easy evaluation of all existing predicates in templates in the form tg.acess.has_permission('edit'). We could also provide a mechanism for including additional custom predicates in the access object.