OD123 patch-at-import¶
Code run at import patches Odoo, for every database the server runs.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Warning | all | no |
What it reports¶
A statement at the top level of a file, or in an if, try or with block there, that sets an
attribute on a name the file imports from odoo or from a module under it:
models.BaseModel._x = ..., fields.Field.x += ..., misc.x = ... after
from odoo.tools import misc, SaleOrder._x = ... after
from odoo.addons.sale.models.sale_order import SaleOrder, or setattr(fields.Field, "x", ...).
A patch inside a function, such as a post_load hook, is not reported, and neither is one on a
module the file imports relatively. Neither are a docstring set through __doc__ nor a module
named under odoo.addons, with odoo.addons.x = ... or through sys.modules, since they change
no behaviour.
The message advises inheriting the model when the patched class is a model class: one the index
finds as a model class in the file the import names, such as SaleOrder in
sale/models/sale_order.py. When the addon or that file is not indexed, a class under the addon's
models, wizard, wizards or report package counts as one, and so do BaseModel,
AbstractModel, Model, TransientModel and CachedModel from odoo.models or odoo.orm.
Another class gets the advice to subclass it, and a module the advice to keep the value in the
module itself.
Why it matters¶
Odoo imports each module once per process, at startup for a server-wide module and otherwise the first time a database that has it installed loads, and every database the server runs then shares the classes and modules it imported. An attribute set at import therefore changes the ORM for all of them, including the databases where the module is not installed, and only from the moment the first one loaded: a database's behaviour depends on which other databases the worker served before.
A model class that inherits the model changes it only in the registries of the databases that have
the module installed. Override the method there and call super(). For another class, use a
subclass of it in the module's own code, and keep a value the module needs in the module itself.
Example¶
from odoo import models
def _x_greeting(self):
return f"Hello {self.display_name}"
models.BaseModel._x_greeting = _x_greeting
Every model of every database on the server gains _x_greeting(), with this module installed there
or not.
from odoo import models
class ResPartner(models.Model):
_inherit = "res.partner"
def _x_greeting(self):
return f"Hello {self.display_name}"