---
url: https://docs.cybrosys.com/vs-code-extension/features/code-inspection.md
description: >-
  Optional warnings for Odoo coding guidelines in Python and XML files, off by
  default in Odoo Helper for VS Code.
---

# Code inspection

Get warnings in Python and XML files when your code departs from Odoo's coding guidelines. The checks run as you open, edit and save a file, and appear in the editor and the **Problems** panel.

## What you can do

The checks follow [Odoo's coding guidelines](https://www.odoo.com/documentation/master/contributing/development/coding_guidelines.html). Every finding is a **Warning**, shown on the line that triggers it. The checks cover `.py` and `.xml` files. They do not cover CSV files such as `ir.model.access.csv`.

### Python: model files

These checks run on Python files in a `models/` folder.

| Rule | Warning example | Flagged code |
|---|---|---|
| File name matches the class. `SaleOrder` goes in `sale_order.py`. | `File name should be 'sale_order.py' for class 'SaleOrder'` | `class SaleOrder(models.Model)` in `saleorder.py` |
| Model classes use CamelCase. | `Model class 'sale_order' should use CamelCase` | `class sale_order(models.Model):` |
| Model `_name` uses the singular. | `Model name 'sale.orders' should use singular form` | `_name = 'sale.orders'` |
| Transient model `_name` follows `<base_model>.<action>`. | `Transient model name should follow pattern '<base_model>.<action>'` | `_name = 'saleorderimport'` in a `TransientModel` |

### Python: all files

| Rule | Warning example | Flagged code |
|---|---|---|
| Do not use `.clone()`. Use `dict(my_dict)` or `list(old_list)`. | `Don't use .clone()` | `new_dict = old_dict.clone()` |
| Do not call `cr.commit()` yourself. | `NEVER call cr.commit() yourself unless you created your own cursor` | `self.env.cr.commit()` |
| Do not format a string before translating it. | `Don't format strings before translation` | `_('Hello %s' % name)` |
| Do not concatenate inside `_()`. Write the full string. | `Don't use concatenated strings inside translation functions` | `_('Hello ' + name)` |
| Do not format after translating. | `Don't format after translation` | `_('Hello') % name` |
| Do not nest `_()` calls. | `Don't nest translation calls` | `_('Name: %s' % _(self.name))` |
| Test a collection directly. | `Use 'if collection:' instead of 'if len(collection) > 0:'` | `if len(records) > 0:` |
| Iterate a dictionary directly. | `Use 'for key in my_dict:'` | `for key in my_dict.keys():` |
| Do not pass `None` as the default of `.get()`. | `.get('key', None) is redundant` | `my_dict.get('foo', None)` |
| `Many2one` field names end in `_id`. | `Many2One field 'partner' should have '_id' suffix` | `partner = fields.Many2one('res.partner')` |
| `One2many` and `Many2many` field names end in `_ids`. | `One2Many field 'lines' should have '_ids' suffix` | `lines = fields.One2many('sale.order.line', 'order_id')` |
| `action_` methods call `self.ensure_one()` near the top. | `Action methods should call self.ensure_one() at the beginning` | `def action_confirm(self):` without `self.ensure_one()` in the next few lines |
| Imports are ordered: standard library, then `odoo`, then `odoo.addons`. | `Wrong import order. Should be: 1) Python stdlib, 2) Odoo core, 3) Odoo addons` | `import os` below `from odoo import api` |

### Python: method names

A method whose name contains one of these keywords must start with the matching prefix.

| Keyword | Required prefix | Flagged | Accepted |
|---|---|---|---|
| compute | `_compute_<field_name>` | `compute_amount_total` | `_compute_amount_total` |
| search | `_search_<field_name>` | `search_partner` | `_search_partner` |
| default | `_default_<field_name>` | `default_currency` | `_default_currency` |
| selection | `_selection_<field_name>` | `selection_state` | `_selection_state` |
| onchange | `_onchange_<field_name>` | `onchange_partner_id` | `_onchange_partner_id` |
| check | `_check_<constraint_name>` | `check_amount_total` | `_check_amount_total` |
| action | `action_<action_name>` | `do_action` | `action_confirm` |

### XML

| Rule | Warning example | Flagged code |
|---|---|---|
| `id` comes before `model` on `<record>`. | `Place 'id' attribute before 'model' in <record>` | `<record model="ir.ui.view" id="sale_order_view_form">` |
| `name` is the first attribute of `<field>`. | `The 'name' attribute should be the first in <field>` | `<field type="char" name="name">` |
| Put `noupdate="1"` on `<odoo>`, not on `<data>`. | `Use noupdate="1" on <odoo> tag instead of <data>` | `<data noupdate="1">` |
| Use `<menuitem>`. | `Use <menuitem> tag instead of <record model="ir.ui.menu">` | `<record id="menu_sale" model="ir.ui.menu">` |
| View record IDs follow `<model>_view_<type>`, with `_inherit` for inherited views. | `View ID 'view_sale_order_form' should follow pattern: <model_name>_view_<view_type>` | `<record id="view_sale_order_form" model="ir.ui.view">` |
| View names use dots: `<model.name>.view.<type>`. | `View name 'sale_order_view_form' should use dots instead of underscores` | `<field name="name">sale_order_view_form</field>` |
| Inherited view names contain `.inherit.<details>`. | `Inherited view name '...' should contain '.inherit.<details>' suffix` | `<field name="name">sale.order.view.form.partner</field>` |

View types in IDs and names are `form`, `list`, `kanban`, `search`, `calendar`, `graph`, `pivot` and `activity`.

IDs that contain a keyword must match a pattern. IDs without the keyword are not checked.

| ID contains | Pattern | Example |
|---|---|---|
| `_menu` | `<model>_menu` or `<model>_menu_<detail>` | `sale_order_menu`, `sale_order_menu_main` |
| `_action` | `<model>_action` or `<model>_action_<detail>` | `sale_order_action` |
| `_group_` | `<module>_group_<group_name>` | `sale_group_manager` |
| `_rule_` | `<model>_rule_<group>` | `sale_order_rule_company` |

### File names

The check uses the name of the folder that holds the file.

| Folder | File | Rule |
|---|---|---|
| `views/` | XML | Ends with `_views.xml`, `_templates.xml` or `_menus.xml`. |
| `security/` | XML | Ends with `_groups.xml` or `_security.xml`. |
| `report/` | XML | Ends with `_report_views.xml`, `_reports.xml` or `_templates.xml`. |
| `wizard/` | XML | Ends with `_views.xml`. |
| `data/` | XML | Ends with `_data.xml` or `_demo.xml`. |
| `controllers/` | Python | Snake case: lowercase letters and `_`. |
| `wizard/` | Python | Snake case: lowercase letters and `_`. |
| `report/` | Python | Ends with `_report.py`. |

## Get started

The linter is off by default. To turn it on:

1. Open **Settings** and search for `Enable Code Standard Warnings`, or set `cybrosys-assista-odoo-helper.enableCodeStandardWarnings` to `true`.
2. Open a Python or XML file in an Odoo module and edit it. Warnings appear in the editor and in the **Problems** panel (`Ctrl+Shift+M`, or `Cmd+Shift+M` on macOS).

Turn the setting off to clear the warnings.

## Tips and limits

* Guidelines change between Odoo releases. Check the current [Odoo coding guidelines](https://www.odoo.com/documentation/master/contributing/development/coding_guidelines.html) if a warning looks wrong for your version.
* The checks are a subset of the guidelines, not a full replacement for review. They match text on one line at a time, so a tag whose attributes span several lines is not checked.
* The checks are approximate and can flag valid code:
  * The translation rule looks for `%` inside `_()`, so it also flags the recommended `_('Hello %s', name)`.
  * The method rule looks for the keyword anywhere in the name. `research_topics` (contains `search`) and `_compute_default_price` (contains `default`) are flagged.
  * The plural rule flags a model name whose last word ends in `s`, such as `x.status`.
  * Elements inside a view's `arch` that have an `id` attribute are tested against the view ID pattern.
* [Model tools](/vs-code-extension/features/model-tools) write view IDs such as `sale_order_form_view` and report files named `report/<model>_pdf_report.xml`. Both fail these rules. Rename them if you want a clean Problems panel.
* You cannot turn off individual rules. The setting enables or disables all of them.

## Next steps

* [Smart suggestions](/vs-code-extension/features/smart-suggestions)
* [Module templates](/vs-code-extension/features/module-templates)
