OD302 xmlid-not-in-depends¶
The XML id comes from a module missing from depends.
| Category | Severity | Series | Needs the index |
|---|---|---|---|
| Correctness | Error | all | yes |
What it reports¶
A reference to an XML id defined by a module that is not among the referencing module's
dependencies, direct or transitive. The references checked are the same as for
OD301: ref attributes and the other references in data files, and env.ref() in
Python. In a data file it also reports an id whose module is neither in depends nor on the
addons path. A module that Odoo always installs with base, such as web, counts as in
depends. From saas~14.3, where a data file names web.assets_backend, web.assets_common or
web.assets_frontend, OD328 reports the element instead.
Why it matters¶
Odoo loads modules in the order their depends set. A module that names another's id without
depending on it works in a database where that module happens to be installed and loaded first,
and fails in one where it is not: the data file stops the install with "External ID not found in
the system", and env.ref() raises ValueError when the line runs. A demo file differs: see load
failures. Tests in a full database pass,
and the failure shows up on a customer's lean one.
In Python, only ids of indexed modules are checked, because code often names an Enterprise or
optional module's id behind a check that the module is installed. Groups given to has_group()
or a field's groups are not reported here, for the same reason. Upgrade scripts under
migrations/ and upgrades/ are skipped, since they name ids of past versions.
The rule stays silent on an id that a dependency that is not indexed, such as an Enterprise module,
could bring in: an id of a module that is not indexed either, or one that an indexed module outside
depends defines. It still reports an id that an indexed module outside depends does not define,
unless that module loads a data file the scan cannot read. Add the checkout of the dependency that
is not indexed to --addons-path to check the other ids.
An env.ref() in code that runs only once a check at runtime has passed can get no finding,
since a soft dependency is meant to be absent at times. OD206 lists the
checks and the code they cover, such as a try that catches the failed lookup and skips from every
handler; one that carries on after the error guards nothing, so the rule reports what it holds.
A check covers an id only when the id's module comes with what the check names: the module of
self.ensure_installed("m"), of _get("m"), of a search by name or of "m" in ..._installed(),
and each module that introduces a model it tests for. A guarding try names the modules of the ids
it looks up: inside its body every caught lookup counts, and after it only the lookups that run on
every path through the body.
Those modules bring their depends. They also bring each module that auto-installs once its triggers
are installed, when at least one trigger is among them and every other one is too or comes with the
referencing module (in its depends, direct or transitive, or among the modules Odoo always installs
with base). An auto-installed module whose triggers all come with the referencing module owes
nothing to the check, and an id of it reports as it would without one. For example,
self.ensure_installed("sale") covers an id of sales_team, and a check on purchase covers one of
purchase_stock in a module whose depends bring in stock_account.
A check that names nothing the scan reads, such as hasattr or the result of a check held in a name
or a self attribute, or that names a module or a model the scan does not index, covers every id
behind it. OD301 still reports an id behind a check when its module is in depends and
does not define it.
Example¶
class SaleOrder(models.Model):
_inherit = "sale.order"
def _rush_picking_type(self):
return self.env.ref("stock.picking_type_out")
The module depends on sale only, and sale does not depend on stock, so the id exists only
when some other module has installed stock.
sale_stock depends on both sale and stock. When no such module fits, list the module that
defines the id in depends yourself.