0

I had created a decorator to check if a person has session as follows: (comments added for brevity)

def session_enabled(func=None, prefix='calling: '):
      # some preprocessing
      def session_enabled_wrapper(*args, **kwargs):
           # check for session in request obj
           # execute the function and get result onto a variable say result
           # some API profiling logic
           return result
      return session_enabled_wrapper

I have used this on some views as follows:

@session_enabled
@csrf_exempt
def view_function(request):
     # some processing

My goal was to check if any function are being accessed without this decorator in place on the logs. So i wrote a middleware as follows:

class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''

    def process_view(self, request, view_func, view_args, view_kwargs):
         '''
         called during the request cycle
         :param request: request param
         :param view_func: view function object
         :param view_args: args passed to view function
         :param view_kwargs: kwargs passed to view function
         :return: None
         '''
         print('############# Inside session enabled middleware ###################')
         if not view_func.__name__ == 'session_enabled_wrapper':
                print('Function Not session enabled', request.path)
         else:
                print('function is session enabled', request.path)

I added the above middleware to tuple of MIDDLEWARE_CLASSES in settings.py file. I was happy as this worked, but the happiness was short lived as my APIs started to crash with 403 forbidden error.

After some research, i changed the decorator as follows:

import functools
def session_enabled(func=None, prefix='calling: '):
      # some preprocessing
      @wraps(func)
      def session_enabled_wrapper(*args, **kwargs):
           # check for session in request obj
           # execute the function and get result onto a variable say result
           # some API profiling logic
           return result
      return session_enabled_wrapper

This meant that my earlier middleware logic failed. I needed to overcome this. So changed my middleware and decorator as follows:

decorator:

def session_enabled(func=None, prefix='calling: '):
    # some preprocessing
    @wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.session_enabled = True
        # check for session in request obj
        # actual function execution and get result onto a varible say result
        # some API profiling logic
        return result
    wrapper.session_enabled = False
    return wrapper


middleware:

class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''

    def process_view(self, request, view_func, view_args, view_kwargs):
       '''
       called during the request cycle
       :param request: request param
       :param view_func: view function object
       :param view_args: args passed to view function
       :param view_kwargs: kwargs passed to view function
       :return: None
       '''
       print('############# Inside session enabled middleware ###################')
       if not view_func.session_enabled:
            print('Function Not session enabled', request.path)
       else:
            print('function is session enabled', request.path)

But i was greeted with function object has no attribute 'session_enabled'.

I even tried:

view_function.__closure__[0].cell_contents.__name__ 

but couldn't get the name of the decorator.

What am i doing wrong? Is there any possible way to get the name of the decorator to be used as a condition in middleware or a way to find if the function is decorated and take necessary actions?

Note: Stackoverflow question which almost meet the above requirement: Detect Decorator in Python


EDIT:

After considering Vitor Freitas recommended link i changed the code as follows:

@register(session_enabled, csrf_exempt)
def view_function(request):
      # some processing

middleware:

class SessionEnabledMiddleware(object):
'''
class that represents middleware called during requests
'''

    def process_view(self, request, view_func, view_args, view_kwargs):
       '''
       called during the request cycle
       :param request: request param
       :param view_func: view function object
       :param view_args: args passed to view function
       :param view_kwargs: kwargs passed to view function
       :return: None
       '''
        try:
             print('############# Inside session enabled middleware ###################')
             decorators = [decorator.__name__ for decorator in view_func._decorators]
             if 'session_enabled' in decorators:
                    print('Function is session enabled', request.path)
        except:
             print('function is not session enabled or decorated using register', request.path)

Work's like a charm.....

Adarsh
  • 3,273
  • 3
  • 20
  • 44
  • That's a tough one. Have you seen this question: [Introspection to get decorator names on a method?](https://stackoverflow.com/questions/3232024/introspection-to-get-decorator-names-on-a-method) Maybe it can provide some insights. But from what you've described, I'm not sure if a Middleware would be the best solution for this problem. If your goal is to audit and make sure all your views are decorated with `@session_enabled`, maybe in the unit tests would be a more suitable place for this kind of check? You would also eliminate the overhead of executing this middleware on every request. – Vitor Freitas Feb 13 '18 at 21:09
  • My plan was to introduce this middleware, log the View names along with the api path in redis over a period of 1 month and then disable it and find out the apis that arent session enabled. It seems the above isn't possible with the current knowledge I have. This has been asked in the past too. Maybe as you mentioned, this isn't the right way to do it. Thanks for your time :) – Adarsh Feb 14 '18 at 02:35

0 Answers0