views:

91

answers:

4

Hi,

I'm trying to get a local variable from a decorator. An example:

def needs_privilege(privilege, project=None):
    """Check whether the logged-in user is authorised based on the
    given privilege

    @type privilege: Privilege object, id, or str
    @param privilege: The requested privilege"""

    def validate(func, self, *args, **kwargs):
        """Validator of needs_privillige"""
        try: check(self.user, privilege, project)
        except AccessDenied:
            return abort(status_code=401)
        else: 
            return func(self, *args, **kwargs)

    return decorator(validate)

After decorating a function, like this:

 @needs_privilege("some_privilege")
 def some_function():
     pass

I would like to retrieve the 'privilige' variable (which validate() uses) from some_function. After searching more than one hour, I'm feeling pretty lost. Is this possible?

Edit: Let me describe my problem a bit more thoroughly: can I get the string "some_prvilege" without executing some_function? Something like:

a = getattr(module, 'somefunction')
print a.decorator_arguments

? Thanks for helping me so far!

+2  A: 

You could pass it as a parameter:

def needs_privilege(privilege, project=None):
    """Check whether the logged-in user is authorised based on the
    given privilege

    @type privilege: Privilege object, id, or str
    @param privilege: The requested privilege"""

    def validate(func, self, *args, **kwargs):
        """Validator of needs_privillige"""
        try: check(self.user, privilege, project)
        except AccessDenied:
            return abort(status_code=401)
        else: 
            return func(self, privilege, *args, **kwargs)

    return decorator(validate)

@needs_privilege("some_privilege")
def some_function(privilege):
    pass
Radomir Dopieralski
Thanks for responding! Not quite what I'm looking for though. I want to get the argument passed to needs_privilege *without* executing the real function (some_function, in this scenario).
Mzialla
+3  A: 

Your decorator basically check if a user have the permission to execute a given function, i don't actually understand why you want to retrieve (to attach) the privilege to the function that was being wrapped but you can do this without adding another argument to all your functions.

def needs_privilege(privilege, project=None):
    """Check whether the logged-in user is authorised based on the
    given privilege

    @type privilege: Privilege object, id, or str
    @param privilege: The requested privilege"""

    def validate(func, self, *args, **kwargs):
        """Validator of needs_privillige"""
        try: check(self.user, privilege, project)
        except AccessDenied:
            return abort(status_code=401)
        else:
            return func(self, *args, **kwargs)
    validate.privelege = privelege
    return decorator(validate)

by the way your decorator should be like this :

def needs_privilege(privilege, project=None):
    def validate(func):
        def new_func(self, *args, **kwargs):
            try: 
                check(self.user, privilege, project)
            except AccessDenied:
                return abort(status_code=401)
            else:
                return func(self, *args, **kwargs)
        new_func.privilege = privilege
        return new_func
    return validate
singularity
Thanks, but it's not what I'm looking for, sorry. I would like to retrieve 'privilege' without actually executing the function. Please see my edit.
Mzialla
Mzialla: is this work for you now :)
singularity
Yes, thank you very much!
Mzialla
A: 

Functions are objects that can have attributes too. You can set attributes in the decorator. Here's an example:

class TestClass(object):
    def needs_privilege(privilege, project=None):
        def wrapper(func):
            def validate(self, *args, **kwargs):
                """Validator of needs_privillige"""
                print 'validator check for %s' % privilege
                return func(*args, **kwargs)
            validate.privilege = privilege
            return validate

        return wrapper

    @needs_privilege("foo")
    def bar():
        print "called"

>>> test.TestClass().bar()
validator check for foo
called
>>> test.TestClass.bar.privilege
'foo'
>>> test.TestClass().bar.privilege
'foo'
Robie Basak
Thanks for your answer! Like I said to `unutbu`, it's a pity I can only pick one answer!
Mzialla
+1  A: 

Your problem would be much simpler if you didn't need the decorator module. If you don't strictly need the decorator module, you could write the decorator like this:

def needs_privilege(privilege, project=None):
    def validate(func):
        def _validate(self, *args, **kwargs):
            return func(self, *args, **kwargs)
        _validate.decorator_args=(privilege,project)
        return _validate
    return validate

@needs_privilege("some_privilege")
def some_function(self):
    pass

a = some_function
print(a.decorator_args)
# ('some_privilege', None)
unutbu
+1 I was trying to find a way to say this same thing. The decorator package adds an extra layer of complexity to the problem.
ma3
Thanks! It's a pity I can only pick one answer as solution.
Mzialla