Home > database >  Python How to call child class method from Parent metaclass
Python How to call child class method from Parent metaclass

Time:08-31

I am trying to write my own implementation of test runner, what I struggle with is some kind of setUp and TearDown methods and how to override/invoke them.

class MetaTestCase(type):

    def __call__(self, *args, **kwds):
        return super().__call__(*args, **kwds)

    def __new__(self, name, bases, attrs):
        def replaced_fnc(fn):
            def new_test(*args, **kwargs):
                self.before(self)
                result = fn(*args, **kwargs)
                self.after(self)
                return result

            return new_test

        for i in attrs:
            if callable(attrs[i]):
                attrs[i] = replaced_fnc(attrs[i])

        return (super(MetaTestCase, self).__new__(self, name, bases, attrs))

    def before(self):
        print('Before')

    def after(self):
        print('After')


class TestCase(metaclass=MetaTestCase):
    pass


class TestSuite(TestCase):

    def before(self):
        print('New Before')

    def after(self):
        print('New After')

    def test(self):
        print("Test")


if __name__ == "__main__":
    TS = TestSuite()
    TS.test()

The current output of that is:

Before
Test
After

But the expected output would be to override those functions from metaclass with those from Child Class like that:

New Before
Test
New After

But I don't really know metaclasses very good and how to pass Child methods to the Parent class.

CodePudding user response:

Like chepner suggest u don't need a metaclass for this. Define a test runner that takes the suite TS as an argument, and it just calls TS.before, TS.test, and TS.after explicitly and in sequence.

I just answer to question, how to call extra method from metaclass

Here u can read more aboute metaclasses. But quick answer will be, just use polymorphism.

So first of all u need to move your before and after method to parent class(not metaclass). In python when we work with objects, first argument is always self so we can use that like: args[0].before()

Next problem is infinite loop. We need to decied which function we need to overwrite in meta class, in my answaer I simple check if method name contain 'test', but u can create smth more sophisticated

class MetaTestCase(type):

    def __call__(self, *args, **kwds):
        return super().__call__(*args, **kwds)

    def __new__(self, name, bases, attrs):
        def replaced_fnc(fn):
            def new_test(*args, **kwargs):
                args[0].before()
                result = fn(*args, **kwargs)
                args[0].after()
                return result

            return new_test

        for i in attrs:
            if callable(attrs[i]) and 'test' in attrs[i].__name__:
                attrs[i] = replaced_fnc(attrs[i])

        return (super(MetaTestCase, self).__new__(self, name, bases, attrs))


class TestCase(metaclass=MetaTestCase):
    def before(self):
        print('Before')

    def after(self):
        print('After')


class TestSuite(TestCase):

    def before(self):
        print('New Before')

    def after(self):
        print('New After')

    def test(self):
        print("Test")


if __name__ == "__main__":
    TS = TestSuite()
    TS.test()
  • Related