Search code examples
pythoninheritanceabstract-class

Inheriting a non-abstract class and turning all of its functions into abstractmethods


An upstream interface was given to me with all of its functions defined as non-abstract when in reality they should be decorated with @abstractmethods. I want to receive an error when I did not implement one of its functions when it's called. To do this, I would create a wrapper class and manually go through each of its defined functions and do something like this:

from abc import ABC, abstractmethod

class Foo(object):
    def foo(self):
        print("Foo")

class AbstractFoo(Foo, ABC):
    @abstractmethod
    def foo(self):
        return super().foo()

class ConcreteFoo(AbstractFoo):
    def foo(self):
        print("Concrete Foo")
        super().foo()

f = ConcreteFoo()
f.foo()

Which outputs:

Concrete Foo
Foo

I would like some way of just doing this to all functions defined by Foo. Obviously, inherited magic functions like __str__ and __repr__ should be forwarded appropriately.

Does anyone know a nice, pythonic way of doing this?


Solution

  • def validate_base_class_implemntation(cls):
        base_cls_funcs = []
        for attr in cls.__bases__[0].__dict__:
            if callable(getattr(cls, attr)):
                base_cls_funcs.append(attr)
    
        cls_funcs = []
        for attr in cls.__dict__:
            if callable(getattr(cls, attr)):
                cls_funcs.append(attr)
    
        missing_funcs = [x for x in base_cls_funcs if x not in cls_funcs]
    
        if len(missing_funcs) > 0:
            print("Not implemented functions are: {}".format(','.join(missing_funcs)))
            raise Exception("Not implement function exception!")
    
        return cls
    
    
    class Foo(object):
        def foo(self):
            print("Foo")
    
        def boo(self):
            print("Wow")
    
    
    @validate_base_class_implemntation
    class ConcreteFoo(Foo):
        def foo(self):
            print("Concrete Foo")
            super().foo()
    
    
    f = ConcreteFoo()
    f.foo()
    

    Not sure in 100% if that what you meant.

    this decorator checks that the class decorated implements all the base class function(in your case, they are not decorated with abstract). if there is a function that your decorated class does not implement, it raises exception.