Le Duy Khanh Le Duy Khanh - 6 months ago 25
Python Question

python using self in decorators in class with kwarg

So I have this set of code, testing decorator

base_permissions_check
:

def authenticated(self,*arg,**kwargs):
function_call = inspect.stack()[1][4][0].strip()
matched = re.match('^self\.', function_call)
if not matched:
raise Exception("function is private")

return self.user.is_authenticated()

def base_permissions_check(func):
def wrap(self,**kwargs):

if not self.authenticated(kwargs):
return self.permissions
# func(kwargs)
return func(kwargs)
return wrap

#public
@base_permissions_check
def has_video_permission(self,**kwargs):


The error says that
authenticated() takes 1 positional argument but 2 were given
when I call has_video_permission. I really don't know what's wrong? while I pass only one kwarg into it

Answer

The wrapped func() function is not bound to the instance as a method, so you need to pass in self explicitly. You also need to apply the kwargs dictionary as separate keyword arguments using the **kwargs call syntax:

return func(self, **kwargs)

Your authenticated method is not actually using the kwargs dictionary you pass in, so you could just call self.authenticated(), but if you need to have access to those keyword arguments, you probably want to use the **kwargs call syntax there too:

if not self.authenticated(**kwargs):

Since you see the error when you call the decorated function, you are probably passing in a positional argument, but your wrapper only accepts keyword arguments (beyond self). Perhaps you want to add *args to handle those positional arguments:

def base_permissions_check(func):
    def wrap(self, *args, **kwargs):

        if not self.authenticated(**kwargs):
            return self.permissions
            # func(kwargs)
        return func(self, *args, **kwargs)
    return wrap

#public
@base_permissions_check
def has_video_permission(self, *args, **kwargs):
    # ...