I want different functions to be executable only if the logged in user has the required permission level.
To make my life more complexly simply I want to use decorators. Below I attempy to set attribute permission
on 'decorated' functions - as shown below.
def permission(permission_required):
def wrapper(func):
def inner(*args, **kwargs):
setattr(func, 'permission_required', permission_required)
return func(*args, **kwargs)
return inner
return wrapper
@permission('user')
def do_x(arg1, arg2):
...
@permission('admin')
def do_y(arg1, arg2):
...
But when I do:
fn = do_x
if logged_in_user.access_level == fn.permission_required:
...
I get an error 'function' object has no attribute 'permission_required'
What am I missing?
Your decorator should return a function that can replace
do_x
ordo_y
, not return the execution result ofdo_x
ordo_y
You can modity you decorate as below:Of course, you have another brief solution:
The problem is that, even though you are setting the desired property to the wrapped function in
inner
,inner
is returning whatever is returned by the decorated function, which usually never is the function itself.You should just return the very same original function with the attribute added, thus you do not really want to worry about what arguments this original decorated function might take, meaning you can get rid of one of the wrapping levels:
This works just fine:
You are checking the attribute on the inner (wrapper) function, but set it on the original (wrapped) function. But you need a wrapper function at all:
Your decorator needs to return something that'll replace the original function. The original function itself (with the attribute added) will do fine for that, because all you wanted to do is add an attribute to it.
If you still need a wrapper, then set the attribute on the wrapper function instead:
After all, you are replacing the wrapped function with the wrapper returned by the decorator, so that's the object you'll be looking for the attribute on.
I also added the
@functools.wraps()
decorator to the wrapper, which copied across important identifying information and other helpful things fromfunc
to the wrapper, making it much easier to work with.