There are a few techniques developer should learn to aid them in their work. In Chapter 1, Getting Started with Odoo Development, we already introduced the user interface Developer Mode. We also have available a server option providing some developer friendly features. We will be describing it in more detail next. After that we will discuss another relevant topic for developers: how to debug server side code.

The Odoo server provides the --dev option to enable some developer features speeding up our development cycle, such as:

The --dev option accepts a comma separated list of options, although the all option will be suitable most of the time. We can also specify the debugger we prefer to use. By default the Python debugger, pdb, is used. Some people might prefer to install and use alternative debuggers. Here also supported are ipdb and pudb.

When working on Python code, the server needs to be restarted every time the code is changed, so that it is reloaded. The --dev command line option makes that reloading: when the server detects that a Python file is changed, it automatically repeats the server loading sequence, making the code change immediately effective.

To use it just add the option --dev=all to the server command:

$ ./odoo-bin -d todo --dev=all

For this to work the watchdog Python package is required, and it should be installed as shown here:

$ pip install watchdog

We all know that a good part of a developer's work is to debug code. To do this we often make use of a code editor that can set breakpoints and run our program step by step.

If you're using Microsoft Windows as your development workstation, setting up an environment capable of running Odoo code from source is a nontrivial task. Also the fact that Odoo is a server that waits for client calls, and only then acts on them, makes it quite different to debug compared to client-side programs.

While it may look a little intimidating for newcomers, the most pragmatic approach to debug Odoo is to use the Python integrated debugger, pdb. We will also introduce extensions to it that provide a richer user interface, similar to what sophisticated IDEs usually provide.

To use the debugger, the best approach is to insert a breakpoint on the code we want to inspect, typically a model method. This is done by inserting the following line in the desired place:

import pdb; pdb.set_trace() 

Now restart the server so that the modified code is loaded. As soon as the program execution reaches that line, a (pdb) Python prompt will be shown in the terminal window where the server is running, waiting for our input.

This prompt works as a Python shell, where you can run any expression or command in the current execution context. This means that the current variables can be inspected and even modified. These are the most important shortcut commands available:

The Odoo server also supports the dev=all option. If activated, when an exception is raised the server enters a post mortem mode at the corresponding line. This is a pdb prompt, such as the one described earlier, allowing us to inspect the program state at the moment where the error was found.

While pdb has the advantage of being available out-of-the-box, it can be quite terse, and a few more comfortable options exist.

Let's see how a simple debugging session looks like. We can start by adding debugger breakpoint in the first line of the do_populate_tasks wizard method:

def do_populate_tasks(self):
    import pdb; pdb.set_trace()
    self.ensure_one()
    # ...

Now restart the server, open a To-do Tasks Wizard form, and click on the Get All button. This will trigger the do_populate_tasks wizard method on the server, and the web client will stay in a Loading… state, waiting for the server response. Looking at the terminal window where the server is running, you will see something similar to this:

> /home/daniel/odoo-dev/custom-addons/todo_wizard/models/todo_wizard_model.py(54)do_populate_tasks()
-> self.ensure_one()
(Pdb)

This is the pdb debugger prompt, and the two first lines give you information about where you are in the Python code execution. The first line informs the file, line number and function name you are in, and the second line is the next line of code to be run.

During a debug session, server log messages can creep in. These won't harm our debugging, but they can disturb us. We can avoid that by reducing the verbosity of the log messages. Most of the time these log messages will be from the werkzeug module. We can silence them using the option --log-handler=werkzeug:CRITICAL. If this is not enough, we can lower the general log level, using --log-level=warn.

If we type h now, we will see a quick reference of the commands available. Typing l shows the current line of code and the surrounding lines of code.

Typing n will run the current line of code and move to the next. If we just press Enter, the previous command will be repeated. So do that three times and we should be at the method's return statement.

We can inspect the content on any variable, such as the open_tasks used in this method. and typing p open_tasks or print open_tasks will show the representation of that variable. Any Python expressions are allowed, even variable assignments. For example, to show a friendlier list with the Task names we could use:

(pdb) p open_tasks.mapped('name')

Running the return line, using n once more, we will be shown the returning values of the function. Something like this:

--Return--
> /home/daniel/odoo-dev/custom-addons/todo_wizard/models/todo_wizard_model.py(59)do_populate_tasks()->{'res_id': 14, 'res_model': 'todo.wizard', 'target': 'new', 'type': 'ir.actions.act_window', ...}
-> return self._reopen_form()

The debugging session will continue on the caller's lines of code, but we can finish it and continue normal execution typing c.