OD211 orphan-super¶
super() calls a method no parent class defines.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Error | all | yes |
What it reports¶
A super().name() call in a model class whose model, and the models it inherits, define no method
name in any other class, and which is not a method of BaseModel such as create, write or
search. A call in the body of a class defined inside a method is not the model's, while one in a
nested function counts. A call inside a hasattr test on the same super() and name cannot fail
and is not reported: write that test around a call whose parent may be missing. Nor is
super().__getattr__() inside __getattr__, where the AttributeError it raises is the answer
that method owes for a missing name. A BaseModel method counts in every series, whichever series
has it, and so does a dunder of BaseModel or object, such as __init__: super() reaches both
at the end of the model's classes. A method BaseModel lost before saas~11.5, such as
create_workflow, counts only in the series that have it, and in none for a module of unknown
series. Classes from modules outside depends count as parents here, because an override of a
method such a module adds is only called by that module. A method of a model reached through
_inherits or delegate=True does not count: the model gets the delegated model's fields, not its
methods, and super() never reaches it. OD312 says what defines a
method.
Why it matters¶
Python looks the method up along the model's classes when the call runs and raises
AttributeError when no class after this one has it. The usual cause is a method renamed or
removed upstream between versions: the override is then never called by Odoo, and calling it
directly fails.
The rule stays silent when it cannot see every parent: a class with a plain Python class among its
bases, a class of the model or of a model it inherits with an _inherit element that is not a
literal, or in a file that does not parse in the module or its dependencies, which
counts as one the scan cannot read, a module whose dependencies include one that is not indexed
(such as an Enterprise module), a model no indexed module defines, and an abstract model, whose
method may come from the models that inherit it. A plain base of another class of the model, which
its file defines above that class with nothing but methods and literals in its body, is read, and
the names it binds count as parent methods.
Example¶
class SaleOrder(models.Model):
_inherit = "sale.order"
def _prepare_invoice_vals(self):
vals = super()._prepare_invoice_vals()
vals["narration"] = self.note
return vals
sale names this method _prepare_invoice, so no parent has _prepare_invoice_vals.
class SaleOrder(models.Model):
_inherit = "sale.order"
def _prepare_invoice(self):
vals = super()._prepare_invoice()
vals["narration"] = self.note
return vals