Code inspection
Get inline warnings in Python, XML and CSV files when your code departs from Odoo conventions. Each warning shows the exact location and the value the plugin expects, and some offer a quick fix. Inspections run as you edit.
What you can do
| File type | What is checked |
|---|---|
| Python | File structure, manifest keys and hooks, model and class names, field names and attributes, function names and decorators. |
| XML | Record and field order, view, menu, action, group and rule names and IDs, and the links between menus and actions. |
| CSV | Structure and naming of ir.model.access.csv. |
Python
File structure
- The file starts with the UTF-8 declaration
# -*- coding: utf-8 -*-. - Imports in
__init__.pyare in alphabetical order, and so are the items infrom odoo import ....
# -*- coding: utf-8 -*-
from . import models
from . import wizards
from odoo import api, fields, modelsManifest (__manifest__.py)
- Required keys are present:
name,summary,description,version,license,categoryandimages. summaryanddescriptionare different, andimagesis not empty.versionuses five numbers, such as16.0.1.0.0.- If you declare a hook (
pre_init_hook,post_init_hook,uninstall_hookorpost_load), the matching function exists inhooks.py.
Models and classes
- The file name matches the model:
sale.orderis insale_order.py. - The class name is PascalCase:
SaleOrder. _nameuses only lowercase letters, dots and underscores._descriptionis set when_nameis set.
Fields
| Rule | Example |
|---|---|
Many2one names end with _id. | partner_id = fields.Many2one('res.partner') |
One2many and Many2many names end with _ids. | line_ids = fields.One2many('sale.order.line', 'order_id') |
| Do not set default values explicitly. | Use fields.Char(), not fields.Char(required=False). The same applies to readonly=False and store=True on stored fields. |
| No conflicting attributes. | fields.Char(required=True, readonly=True) is flagged. |
string starts with a capital letter. | string='Customer Name' |
string is not redundant. | name = fields.Char(string='Name') is flagged because Odoo derives it. |
string and help differ. | string='Description', help='Description' is flagged. |
The redundant-attribute warnings have a quick fix that removes the attribute.
Function names
| Kind | Pattern | Example |
|---|---|---|
@api.onchange | _onchange_<field_name> | _onchange_partner_id |
@api.constrains | _check_<field_name> | _check_amount_total |
| Compute method | _compute_<field_name> | _compute_amount_total |
| Default method | _default_<field_name>, with @api.model | _default_currency_id |
Call a default method from the field with a lambda:
currency_id = fields.Many2one(
'res.currency',
default=lambda self: self._default_currency_id()
)
@api.model
def _default_currency_id(self):
return self.env.company.currency_idXML
Records and fields
- A
<record>hasidandmodelattributes, withidfirst. - A
<field>hasnameas its first attribute. - Non-updatable data sits in
<data noupdate="1">.
Names and IDs
The plugin derives the model name from the file name and the view type from the arch, then checks the pattern.
| Element | Pattern | Example |
|---|---|---|
| View name | <model.name>.view.<type> | sale.order.view.form |
| View ID | <model_name>_view_<type> | sale_order_view_form |
| Menu ID | <model_name>_menu_<description> | sale_order_menu_main |
| Action ID | <model_name>_action | sale_order_action |
| Record rule ID | <model_name>_rule_<group_type> | sale_order_rule_company |
| Group ID | <module_name>_group_<group_name> | sale_management_group_manager |
- A rule counts as a
companyrule when its domain containscompany_id, and as auserrule when it usesbase.group_user. - The module name comes from the file path.
- Menu IDs must match
^[a-z0-9]+(_[a-z0-9]+)*_menu(_[a-z0-9]+)*$.
Cross-checks
The plugin tracks the links between menu items and their actions, and checks them for consistency.
<record id="sale_order_view_form" model="ir.ui.view">
<field name="name">sale.order.view.form</field>
<field name="model">sale.order</field>
<field name="arch" type="xml">
<form>
<field name="name"/>
</form>
</field>
</record>
<menuitem id="sale_order_menu_main"
name="Sales Orders"
action="sale_order_action"
parent="sale.sale_menu_root"/>CSV
For ir.model.access.csv:
- The file has a header and at least one data line.
- The columns
id,nameandmodel_idare present. - Access IDs follow
access_<model_name>and names followaccess.<model.name>, derived from themodel_idvalue. - Quoted fields with commas and escaped quotes are read correctly, and a warning points at the exact field.
model_id | Expected id | Expected name |
|---|---|---|
model_sale_order | access_sale_order | access.sale.order |
model_account_move | access_account_move | access.account.move |
model_res_partner | access_res_partner | access.res.partner |
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_order,access.sale.order,model_sale_order,base.group_user,1,1,1,1
access_account_move,access.account.move,model_account_move,base.group_user,1,0,0,0Get started
Inspections run automatically as you edit. To turn them on or off:
- Open Settings > Editor > Inspections > Cybrosys Assista.
- Select or clear the inspections you want:
| Inspection | Controls |
|---|---|
| Assista Py-Inspection | Python standard inspections |
| Assista XML-Inspection | XML standard inspections |
| Assista CSV-Inspection | CSV standard inspections |
Tips and limits
- Enable all three inspections from the start, and fix warnings as they appear rather than at review time.
- Share your inspection settings with your team so everyone sees the same warnings.
- Guidelines change between Odoo releases. Check the current Odoo coding guidelines if a warning looks wrong for your version.