user724747
user724747

Reputation: 107

How to externalize the decorator in python flask application

I have written a python Flask application, which has a class and methods as below.

class PythonSample:
    def method1():
        pass # does something

    def method2():
        pass # does something

Now I have written another class which has decorator functions as below.

class PythonAuth:
    def oauthAuth():
        pass

Now I'm wiring oauthAuth decorator for all the methods of PythonSample class as below

import oauthAuth from PythonAuth

class PythonSample
    @oauthAuth
    def method1():
        pass # does something

    @oauthAuth
    def method2():
        pass # does something

Applying decorator at each method works fine.

Question: Instead of applying oauthAuth decorator to each of the methods. Is there a way to configure in python, as apply oauthAuth decorator to all the methods in a class and exclude certain methods.

Something like include auth for certain URLs and exclude authentication for certain urls

Please ignore the syntax of the python code here.

Upvotes: 0

Views: 108

Answers (1)

Pedro Rodrigues
Pedro Rodrigues

Reputation: 2648

You can use a class decorator plus some magic.

Decorating Functions

Assume you have a decorator that just logs a string before calling the function.

def log(func):
    def logged_func(*args, **kwargs):
            print('logged')
            func(*args, **kwargs)
    return logged_func

Decorating classes

You can use the same trick, but with a class. log_all is a class decorator, cls is a class type. We use vars to walk the class dictionary, and look for methods by using callable(v). Decorate the method with log(v) and use setattr to change the cls definition to the new decorated method. Just like function decorators, return the class in the end.

def log_all(cls):
    for k, v in vars(cls).items():
            if callable(v):
                    setattr(cls, k, log(v))
    return cls

I am ignoring k essentially, but k is the method name, you could leverage it to achieve your usage scenario.

Full code

Here is a full example, that should make some sense now.

def log(func):
    def logged_func(*args, **kwargs):
            print('logged')
            func(*args, **kwargs)
    return logged_func

def log_all(cls):
    for k, v in vars(cls).items():
            if callable(v):
                    setattr(cls, k, log(v))
    return cls

@log_all
class A:
    def method(self):
            pass

Every method in class A should be decorated with the log decorator.

>>> a = A()
>>> a.method()
logged

Upvotes: 0

Related Questions