3

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!

martineau
  • 119,623
  • 25
  • 170
  • 301
Martijn
  • 586
  • 5
  • 19
  • 1
    Several people have come up with essentially the same answer, but what is unclear is whether or not you need the decorator package (with `decorator(validate)`). Is that a requirement? – snapshoe Oct 17 '10 at 16:33
  • No, it's not a requirement. My question was answered in this thread (see below). Thanks guys/girls! – Martijn Oct 17 '10 at 17:10

4 Answers4

3

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
mouad
  • 67,571
  • 18
  • 114
  • 106
  • 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. – Martijn Oct 17 '10 at 15:22
2

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
  • 2,557
  • 17
  • 14
  • 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). – Martijn Oct 17 '10 at 15:17
1

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
  • 842,883
  • 184
  • 1,785
  • 1,677
0

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
  • 6,492
  • 2
  • 30
  • 34