'How to wrap a base class method in python

Working with python3, I have following classes

class RESTApi:
  def __init__(self):
    self.connection = # Create connection


  def hello_world(self):
    print("Hello World !!")
  ... # More methods


class BaseVM:
  def __init__(self):
    self.restapi = RESTApi()

  def _refresh_restapi_connection(self):
    self.restapi = # Reconnect

class MyClass(BaseVM):
  def __init__(self, *args):
    BaseVM.__init__(self, *args)
  
  def create_user(self, usr, pwd):
    self.restapi.create_user(usr, pwd)

MyClass is where I interact with the existing classes and I can change the code in MyClass but not in the other classes.

The issue I am having is that the REST connection is being cleaned out, when left idle. So I need to implement a call to refresh the REST connection(_refresh_restapi_connection), whenever 'self.restapi.XYZ' fails.

And I want this to be automatically done in try...except. The methods like 'create_user' etc. need not know that there was a reconnect.

Since I can't change the other classes, I am trying to create a wrapper over self.restapi calls

Something of the type:

class RestRetry:
    '''
    Wrapper over RESTApi class instance with retries
    '''
    def __init__(self, vm):
        self._restapi = vm.restapi

    def __getattr__(self, attrb):
        return self.rest_retry(attrb)

    def rest_retry(self, attrb):
        def _retry():
            try:
                # class REST API with retries
                result = getattr(self._restapi, attrb)
            except:
                self._refresh_restapi_connection()
                return getattr(self._restapi, attrb)
            else:
                return result
        return _retry

And then MyClass will have

def __init__(self, *args):
  BaseVM.__init__(self, *args)
  self.restapi = RestRetry()

It doesn't work though

Maybe I am missing something very basic, or maybe trying to solve this the wrong way.



Solution 1:[1]

This is what I eventually ended up writing. Had to change the attribute name in MyClass which I didn't want to but could not get it working without that

class RestRetry:
    '''
    Wrapper over RESTApi class instance with retries
    '''
    def __init__(self, vm):
        self._vm= vm

    def __getattr__(self, attrb):
        return self.rest_retry(attrb)

    def rest_retry(self, attrb):
        def _retry(*args, **kwargs):
            try:
                # class REST API with retries though
                result = getattr(self._vm.restapi, attrb)(*args, **kwargs)
            except:
                self._vm._refresh_restapi_connection()
                return getattr(self._vm.restapi, attrb)(*args, **kwargs)
            else:
                return result
        return _retry

And then in MyClass

def __init__(self):
    BaseVM.__init__(self)
    self._restapi = self.RestRetry(self)


def any_method(self):
    self._restapi.hello_world()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mittal