Skip to content

OD000 syntax-error

The file does not parse.

Category Severity Series Needs the index
Correctness Error all no

What it reports

A Python file that is not valid Python, an XML file that is not well-formed XML, a CSV data file whose header row cannot be read, or a script that is not a valid ES module. Scripts are checked when a bundle loads them as ES modules, as for OD601. The finding points at the first error the parser meets, and its message is the parser's own. Nothing else is checked in that file, so fixing it can bring other findings to light.

async and await are reserved words from 15.0, whose floor is Python 3.7, so a Python file using either as a name fails there: rename it. Below 15.0, and in a module of unknown series, the rule reads them as names outside an async def block, even on an install running a newer Python.

9.0 and 10.0 run on Python 2.7. There, a Python file that does not parse as Python 3 is read again with the Python 2 forms their core writes: a print or exec statement, raise E, "message", <>, an octal integer such as 0644, a long integer such as 10L, a ur"..." string, backticks, tuple parameters, True or False as a name, and tabs that indent to stops of 8. A file that parses so gets no finding; otherwise the finding points at the first error left. In a module being checked, a notice names the file, at the place Python 3 stops, and says it is not checked; in a module on the addons path it gets no notice. This reads Python 2 only roughly: a file that also holds Python 3-only syntax gets the notice. Every other series is read as Python 3, as is a module whose manifest names no series unless --odoo-version gives one.

Why it matters

Odoo imports a module's Python package when it loads the module, and a SyntaxError in any file the package imports stops the load: the module cannot be installed, and a database that already has it fails to start. An XML or CSV data file is parsed when the module is installed or updated, and a parse error stops that install or update. A demo file differs: see load failures. A script that does not parse stops the web client bundle it is in.

An empty XML file is not reported. An XML data file is read in the encoding it declares, as Odoo reads it, when that is UTF-8, Latin-1 or Latin-9. A data CSV reads as UTF-8, and below 11.0 each cell falls back to Latin-1, as Odoo reads it. A file that does not decode gets no finding: save it as UTF-8 to have it checked. A __manifest__.py that does not parse is not reported either: without a readable manifest, odooscan does not treat the directory as a module. The CSV reader is lenient and reads a row with an unclosed quote or a missing column as best it can.

A data file the manifest loads that stays unread, because it does not decode or this rule reports it, may define what other rules look for. In its module and in the modules that depend on it, rules stay silent on an XML id of its module, a view or template element, a view type an action lists, a model no class defines that a data file names, a field missing from a model, and a field a <record> writes or leaves out. OD401 also counts it as a possible access row.

Such a file holds no Python or JS, and it loads after the Python of its module and ahead of the modules that depend on it, so these are still reported:

  • Rules on Python methods, Python classes and JS members, and a model or a field that only a module outside depends defines.
  • A field activity_ids the model lacks (OD318), as a field a data file adds is named x_.
  • In its module, a path Odoo resolves as it sets up a model (OD203), which comes ahead of the file.
  • In a module that depends on it, a field missing from a model that module defines whole, and the value a record gives a field (OD321, OD322): the file has already loaded, so it can neither extend that model nor replace that value. Fields named on a <record> and in a view modifier stay silent all the same.

A Python file this rule reports, or one a Python 2 notice names, may define what other rules look for too. The models its classes name count as defined, with their ir.model XML ids, so OD201 and OD301 stay silent on them, and OD202 names the module of the file. Its fields are not read, so OD301 still reports the XML id of one. Other rules on a field of such a model, or of a model that inherits or delegates to it, stay silent in that module and in the modules that depend on it, since the file may add any. Rules on a method stay silent on such a model and on a model that inherits it, but not on one that delegates to it, which gets its fields only.

A class whose model is not spelled out makes its module one that builds model names at runtime, as OD202 describes. In that module, the rules that need every class of a model stay silent on all of its models, whoever defines them: rules on a method, OD210 on a record rule, OD318, OD321 and OD324 among them. Rules that look a field up, such as OD304 and OD309, still report on a model a class in scope introduces. Other modules keep every check on every other model, and a module that does not depend on the file keeps them on its models too: fix the file to have its models checked.

Example

views/sale_order_actions.xml
<odoo>
    <record id="action_small_orders" model="ir.actions.act_window">
        <field name="name">Small orders</field>
        <field name="res_model">sale.order</field>
        <field name="domain">[('amount_total', '<', 100)]</field>
    </record>
</odoo>

A bare < opens a tag in XML, so the domain's comparison breaks the file.

views/sale_order_actions.xml
<odoo>
    <record id="action_small_orders" model="ir.actions.act_window">
        <field name="name">Small orders</field>
        <field name="res_model">sale.order</field>
        <field name="domain">[('amount_total', '&lt;', 100)]</field>
    </record>
</odoo>

Suppressing

Fix the file instead: while it does not parse, nothing else in it is checked. To leave out a file that is not meant to parse, such as a template a script fills in, exclude it:

oscn check . --exclude scaffold/

See suppressing a finding.