The problem isn't with the decorator per se, but with the condition being
evaluated. If you have:
@auth.requires_permission('read')
def secrets():
etc.
that is equivalent to:
@auth.requires(condition=auth.has_permission('read'))
def secrets():
etc.
In this case, the decorator takes an argument (the condition to be
evaluated), and the argument itself is a function call that does a db
query. So, setting up the decorated function ends up running the db query
in auth.has_permission. In trunk, there is a new feature that allows a way
around this -- the condition argument to auth.requires can be a callable,
so you can do:
@auth.requires(lambda: auth.has_permission('read'))
def secrets():
In that case, when the decorator is created, it simply passes the lambda as
the condition, rather than calling auth.has_permission. The lambda doesn't
actually get called until the secrets() function is called.
Perhaps we should change auth.requires_membership and
auth.requires_permission to use lambda in this way.
Anthony
On Friday, November 18, 2011 4:07:28 PM UTC-5, howesc wrote:
>
> the distinction being made here is that decorators appear to be executed
> for methods that are not called during this request. whether or not a
> query is run is not really the point, the point is that it seems that code
> is being executed that the user never intended.
>
> that said, i don't know enough about decorators to know how they work
> under the covers. i would tend to agree with Ids that this behavior is not
> what i expect, and with the auth decorators that run queries can
> significantly slow down an application.
>
> can anyone comment on whether Ids and my expectation of how decorators
> work are correct?
>
> thanks,
>
> cfh
>