Search code examples
pythonodooodoo-12

Skip inheritance order call in odoo


I have a class inherited from project.task named ProjectTask

The class has a copy method that overrides the copy function from project.task it's named Task

I need to run the base copy function from my class instead of the one of the parents class

this is my class code:

@api.multi
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
    if default is None:
        default = {}
    if not default.get('name'):
        default['name'] = self.name.id
    return super(ProjectTask, self).copy(default) #<-- I don't want to call the inherited class method I want to call the base class method instead

This is the copy method from the base class (Task)

@api.multi
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
    if default is None:
        default = {}
    if not default.get('name'):
        default['name'] = _("%s (copy)") % self.name
    return super(Task, self).copy(default) # <-- I want to run this method from my class (ProjectTask) which is the child class

Any advice will be more than welcome


Solution

  • With the parent class implementation you show, calling it with your own default should do what you want, as it will just pass it through to its own parent with no changes. (At least, that's true with the bare method code, I don't know what the odoo decorators do to change things.)

    But if you really do need to skip over it for some non-obvious reason, you probably can do it. Generally speaking, these approaches will only work as intended if you don't expect your class to ever be used with multiple inheritance. If your MRO gets complicated, then you really want to be doing the normal thing with super and making all your methods play nicely together.

    One option for skipping an inherited method is to directly name the class you want your call to go to (i.e. your grandparent class).

    class Base():
        def foo(self):
            print("Base")
    
    class Parent(Base):
        def foo(self):
            print("Parent")
            super().foo()  # super() in Python 3 is equivalent to super(Parent, self)
    
    class Child(Parent):
        def foo(self):
            print("Child")
            Base.foo(self) # call Base.foo directly, we need to pass the self argument ourselves
    

    Another option would be to change the argument you give to super to name the parent class instead of your own class. Usually that's a newbie error, but if that's really what you want, it's allowed (though I'd strongly recommend adding a comment to the code explaining that you really do want that behavior!

    class Child(Parent):
        def foo(self):
            print("Child")
            super(Parent, self).foo()   # Note: Deliberately skipping over Parent.foo here!
    

    A final note: If you find yourself wanting to skip a parent class's implementation of some of its methods, perhaps you should reconsider if you should really be inheriting from it at all. It may be that you really want to be inheriting from the same base class as it instead, and skipping the middle class altogether. Obviously, this has its own limitations (maybe some library code does type checking for that class), but if you find yourself fighting the inheritance machinery, it may be that you're doing things the hard way, and there's an easier alternative.