OD124 module-level-cache¶
A module-level dict, list or set filled at runtime is shared by every database.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Warning | all | no |
What it reports¶
A name the top level of a file binds to a new dict, list or set, that a function or method of the
file changes without binding the name itself: NAME[key] = ..., del NAME[key], or a method that
changes it in place, such as append(), add(), update(), setdefault(), pop() or clear().
The container is a display such as {}, a comprehension, or a call to dict(), list(), set(),
defaultdict(), OrderedDict() or an LRU class. The finding is at the binding, once per name.
A container only the top level of the file fills, a function that binds the name to a container of
its own, and writes whose key holds the database name, such as NAME[self.env.cr.dbname] = ... or
NAME[(self.env.cr.dbname, self.id)] = ..., are not reported.
A memo cache whose value depends only on its key, never on the data of a database, such as the text extracted from a file keyed by the file's checksum, leaks nothing between databases: suppress the finding there.
Why it matters¶
A module is imported once per process, so its globals outlive every request and are shared by all the databases the server runs. A value cached for one database is served to the next: a partner's label, a setting or a record id from another customer. Odoo also runs several worker processes, each with its own copy, and nothing clears the others when the data changes, so two requests see different values depending on the worker that serves them.
tools.ormcache on a model method keeps the cache in the registry of each database, and when code
clears the registry's caches, Odoo clears them in every worker.
Example¶
from odoo import models
_label_by_partner = {}
class ResPartner(models.Model):
_inherit = "res.partner"
def _x_label(self):
if self.id not in _label_by_partner:
_label_by_partner[self.id] = f"{self.ref} {self.name}"
return _label_by_partner[self.id]
Partner 7 of the second database gets the label partner 7 of the first had.
from odoo import models, tools
class ResPartner(models.Model):
_inherit = "res.partner"
@tools.ormcache("self.id")
def _x_label_cached(self):
return f"{self.ref} {self.name}"
def _x_label(self):
return self._x_label_cached()