分享 / Odoo / OdooLS:给 Odoo 开发装一个"懂框架"的语言服务器

OdooLS:给 Odoo 开发装一个"懂框架"的语言服务器

写 Odoo 代码时,最多的两件事是:这个模型上有哪些字段,和这个方法是谁加进来的。普通 Python 工具对这两件事一无所知 —— 因为 Odoo 的扩展模型不是直接通过Python类继承获得的,而是运行时拼出来的。我们在扩展模型中无法定位被扩展模型上定义的变量和方法。

OdooLS 就能很好的解决这一点的。

一、它是什么

OdooLS(odoo/odoo-ls)是 Odoo 官方维护的 Odoo 语言服务器(License: LGPLv3)。

语言服务器 = 实现 LSP 协议的独立进程,所以任何支持 LSP 的编辑器都能接。官方另外提供了几套集成:

编辑器集成
VS Codeodoo/odoo-vscode(应用商店里搜 Odoo)
PyCharmodoo/odoo-pycharm
Neovimodoo/odoo-neovim
Zedodoo/odoo-zed

它提供的能力:自动补全 · 悬停信息 · 跳转定义 · 实时诊断(报错)· 文档符号等。

⭐ 关键在于:它理解 Odoo 的框架语义,而普通的 Python 工具只理解 Python。

二、它解决什么问题

Odoo 的模型由多个模块通过 _inherit 在运行时拼装而成。这对静态分析是灾难:

  • self.env["sale.order"] 在 Pyright 眼里只是 BaseModel —— 没有字段补全、没有方法签名、没有跳转。
  • _inherit 加的字段/方法,静态工具完全看不到 —— 你写 record.x_my_field 它只会说"没有这个属性"。
  • XML 里的 ref="..."、xpath 继承、视图引用的字段 —— 普通编辑器对这些一无所知,改错名字要等运行才炸。
  • 字段与视图的一致性(视图引用了不存在的字段、widget 与字段类型不匹配)—— 只能靠人眼。

OdooLS 的做法是:自己给整个 addons 建索引(读模块清单、Python 源码、XML 视图),在内存里重建一份"Odoo 认为的"符号表。于是上面四件事全部变成编辑器里的补全、跳转与报错。

三、安装

前置

  • 一份 Odoo 源码树(就是能 import odoo 的那个版本,比如 ~/odoo/19.0)
  • 一个能 import odoo 的 Python 解释器(用 venv 最省事)
  • 你的 addons 目录(自己的模块放哪儿)

方式 A:预编译包(推荐,我们用的就是这个)

从 GitHub Releases 下载对应平台的包,把可执行文件放进 PATH:

# 以 macOS arm64 为例,按你的平台换包名
curl -L -o /tmp/odoo-ls.tar.gz \
  https://github.com/odoo/odoo-ls/releases/latest/download/odoo-ls-<platform>.tar.gz
tar -xzf /tmp/odoo-ls.tar.gz -C /tmp
install -m 0755 /tmp/odoo-ls ~/.local/bin/odoo-ls

odoo-ls –version # → odoo_ls_server 1.6.0

⚠️ 版本号有讲究:偶数次版本是正式版(1.4、1.6),奇数次是预发布(1.5)。生产环境用正式版。

方式 B:从源码编译(Rust)

服务端是 Rust 写的(server/ 目录):

git clone https://github.com/odoo/odoo-ls.git
cd odoo-ls/server && cargo install --path .

四、配置

OdooLS 读一份 odools.toml,这是它唯一需要的配置入口:

[[config]]
name = "main"
odoo_path   = "/Users/tony/odoo/19.0"          # 对应版本的 Odoo 源码
addons_paths = ["/path/to/your/addons"]        # 你的模块目录
python_path = "/Users/tony/odoo/.venvs/odoo19/bin/python"

VS Code

应用商店安装 Odoo 扩展(发布者 Odoo),扩展会自己下载并管理语言服务器,并在设置里让你指定 Odoo 源码与 Python。同一扩展还带 release / pre-release 切换(Extensions 面板里的 Switch to Release / Switch to Pre-Release)。

Neovim

官方有 odoo-neovim 集成;也可以直接用任意 LSP 客户端接,本质就是给它一个启动命令 + 上面那份 odools.toml:

vim.lsp.start({
  name = "odoo_ls",
  cmd = { vim.fn.expand("~/.local/bin/odoo-ls"),
          "--config-path", "<你的 odools.toml 路径>" },
  root_dir = <模块根目录>,
})

五、日常怎么用

你的操作ls-odoo
输入 self.env["模型名补全
在 record 上打点字段与方法补全,包含别的模块 _inherit 加进来的(它最值钱的地方)
跳转定义(gd / F12)跳到真正实现它的那个模块,跨 addons 也能跳
悬停字段类型、帮助文本
写错字段名立刻报错,不用等运行
改 XML 视图引用不存在的字段、xpath 不匹配都会报
看一个文件的结构文档符号列表

它把"这个模型到底长什么样"从"运行时才知道"变成"编辑器里就知道"。

六、它不能解决的问题

  • 它不是类型检查器 —— 类型推断远不如 Pyright/mypy 细,两者是互补关系。
  • 动态构造的代码(getattr、字符串拼出来的模型名)它看不到。
  • 它要索引整个 addons —— 首次加载慢、大项目吃内存。
  • 它需要与模块版本一致的 Odoo 源码 —— 版本对不上会给出误导性的报错。