Python class multi-inheritance + MRO

46 Views Asked by At

I've got a Message class with some useful method in it (let's say validate, get_correlation_id, whatever, ...). This class has an init method with some required parameters (type, routing_key, etc...)

I've got a Param class that contains a validate_parameter method.

I've got a Status class that contains a validate_status method.

I've got a JobCreation class that inherits from Message and Param:

class JobCreation(Message, Param):
    msg_type = 'osb.job.ask'

    def __init__(self, parameters = {}, **kwargs):
        # Process reply_to
        reply_to = REPLY_TO_RESULTS
        if 'reply_to' in kwargs:
            reply_to = kwargs['reply_to'] 
            del kwargs['reply_to']

        # Init
        super().__init__(type=self.msg_type, **kwargs, reply_to=reply_to)
        self.parameters = parameters

    def validate(self):
        """Validate the JobCreation"""
        super().validate()
        self.validate_parameters()

I've got a JobResult class that inherits from Message, Param and Status:

class JobResult(Message, Param, Status):
    msg_type = 'osb.job.answer'

    def __init__(self, status=None, parameters={}, **kwargs):
        # Process routing_key
        routing_key = ROUTING_KEY_STATUS
        if 'routing_key' in kwargs:
            routing_key = kwargs['routing_key'] 
            del kwargs['routing_key']

        # Init
        super().__init__(type=self.msg_type, **kwargs, routing_key=ROUTING_KEY_STATUS)
        self.status = status
        self.parameters = parameters

    def validate(self):
        """Validate the JobResult"""
        super().validate()
        self.validate_status()
        self.validate_parameters()

And finally i've got a JobStatus class that inherits from Message and Status:

class JobStatus(Message, Status):
    msg_type = 'osb.job.info'

    def __init__(self, status=None, **kwargs):
        # Process routing_key
        routing_key = ROUTING_KEY_STATUS
        if 'routing_key' in kwargs:
            routing_key = kwargs['routing_key'] 
            del kwargs['routing_key']

        # Init
        super().__init__(type=self.msg_type, **kwargs, routing_key=ROUTING_KEY_STATUS)
        self.status = status

    def validate(self):
        """Validate the JobStatus"""
        super().validate()
        self.validate_status()

As you can see, depending on the type of 'Job' initialized, I want to validate it but it could be a parameter validation, a status validation or both.

The problem is, in my unit tests, it raises an error like this :

    class JobStatus(Message, Status):
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I've tried to create a Base class inheriting from ABC (abstract base class), and make my Message, Status and Param classes inherit from Base - doesn't seem to work.

Do you know how can I fix it?


[EDIT] As asked, the minimal reproductible example:

class Message:
    def __init__(self):
        print('Message init')

    def validate(self):
        print('Message validation')

class Status:
    def validate_status(self):
        print('Status validation')

class Param:
    def validate_parameters(self):
        print('Parameters validation')


class JobCreation(Message, Param):

    def __init__(self):
        print('Jobcreation init')
        super().__init__()

    def validate(self):
        super().validate()


class JobResult(Message, Param, Status):

    def __init__(self):
        print('Jobresult init')
        super().__init__()

    def validate(self):
        super().validate()
        self.validate_status()
        self.validate_parameters()

class JobStatus(Message, Status):

    def __init__(self):
        print('Jobresult init')
        super().__init__()

    def validate(self):
        super().validate()
        self.validate_status()


if __name__ == "__main__":
    job_creation = JobCreation()
    job_creation.validate()

    job_result = JobResult()
    job_result.validate()

    job_status = JobStatus()
    job_status.validate()
0

There are 0 best solutions below