0

I am writing a webapi using flask and flask-restplus. I have created a decorator to calculate the time to execute api call.

import time

class TimeCalculateDecorator:

    def __init__(self, func): 
        self.function = func 

    def __call__(self,*args, **kws): 
            ts = time.time()
            result = self.function(*args, **kws)
            te = time.time()
            print('func:%r args:[%r, %r] took: %2.4f sec' % \
              (self.function.__name__, args, kw, te-ts))
            return result

this is how I am using it...

class MultipleEmp_controller(Resource):


    @inject
    def __init__(self,api, dataservice:DataServiceBase):
        self.service = dataservice

    @TimeCalculateDecorator
    def get(self):
        """Get Request for version 1"""
        emp_schema = EmployeeSchema(many=True)
        emps = emp_schema.dump(self.service.getemployees())
        return emps

The problem comes when decorator calls above controller method and found self argument is missing from there. Here is the exact error message...

"get() missing 1 required positional argument: 'self'",

I tried google but no luck.

I tried with simple method decorator like below...

def timeit(method):
    def timed(*args, **kw):
        ts = time.time()
        result = method(*args, **kw)
        te = time.time()
        print('func:%r args:[%r, %r] took: %2.4f sec' % \
          (method.__name__, args, kw, te-ts))
        return result
    return timed

and this is working perfectly fine. The issue comes when I make it as class, not as method.

davidism
  • 121,510
  • 29
  • 395
  • 339
Abhash786
  • 881
  • 2
  • 24
  • 53
  • read this https://medium.com/pythonhive/python-decorator-to-measure-the-execution-time-of-methods-fa04cb6bb36d – Drako Mar 03 '20 at 07:42
  • Hi Drako... thanks for your response... but I have already tried that... it is created as method decorator and I want it as class.... – Abhash786 Mar 03 '20 at 08:15
  • here you will find class examples: https://realpython.com/primer-on-python-decorators/#functions – Drako Mar 03 '20 at 09:25

1 Answers1

0

Your TimeCalculateDecorator is calling the wrapped function without passing in a reference to the correct MultipleEmp_controller instance.

I'm not sure how you would get the referencing correct using pure decorators, but here is a way to implement decorating the method during class initialisation:

import time

class TimeCalculateDecorator:
    def __init__(self, func, **kwargs): 
        self.function = func 

    def __call__(self,*args, **kws): 
            ts = time.time()
            result = self.function(*args, **kws)
            te = time.time()
            print('func:%r args:[%r, %r] took: %2.4f sec' % \
              (self.function.__name__, args, kws, te-ts))
            return result

class MultipleEmp_controller(object):
    def __init__(self, *args, **kwargs):
        self.get = TimeCalculateDecorator(self.get)
        return  

    def get(self):
        """Get Request for version 1"""
        print('called')
        return 


if __name__ == '__main__':
    x = MultipleEmp_controller()
    x.get()

Also, worth reviewing this answer.

Ian Ash
  • 1,087
  • 11
  • 23
  • Thanks Ian... I have tried this already and it is working. but as you also mentioned it is not pure decorator and I want it using decorator only – Abhash786 Mar 04 '20 at 11:28