odoo-typegen 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo_typegen-0.1.2/LICENSE +21 -0
- odoo_typegen-0.1.2/PKG-INFO +258 -0
- odoo_typegen-0.1.2/README.md +231 -0
- odoo_typegen-0.1.2/pyproject.toml +59 -0
- odoo_typegen-0.1.2/src/odoo_typegen/__init__.py +1 -0
- odoo_typegen-0.1.2/src/odoo_typegen/cli.py +87 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/__init__.py +0 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/compiler.py +288 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/consolidated_model.py +34 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/core_stub_compiler.py +216 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/environment_compiler.py +74 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/model_compiler.py +79 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/model_fragment.py +12 -0
- odoo_typegen-0.1.2/src/odoo_typegen/compiler/model_index.py +18 -0
- odoo_typegen-0.1.2/src/odoo_typegen/emitter/__init__.py +1 -0
- odoo_typegen-0.1.2/src/odoo_typegen/emitter/type_emitter.py +134 -0
- odoo_typegen-0.1.2/src/odoo_typegen/registry/__init__.py +0 -0
- odoo_typegen-0.1.2/src/odoo_typegen/registry/module.py +9 -0
- odoo_typegen-0.1.2/src/odoo_typegen/registry/registry.py +29 -0
- odoo_typegen-0.1.2/src/odoo_typegen/registry/registry_service.py +87 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jb
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: odoo-typegen
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Static type discovery and stub generation for Odoo addons.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: odoo,typing,stubs,pyright
|
|
7
|
+
Author: jb
|
|
8
|
+
Author-email: jeanb.rocher@gmail.com
|
|
9
|
+
Requires-Python: >=3.10,<3.14
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Requires-Dist: astroid (>=3.3.10,<5.0.0)
|
|
20
|
+
Requires-Dist: cyclopts (>=3.22.5,<5.0.0)
|
|
21
|
+
Requires-Dist: pydantic (>=2.11.7,<3.0.0)
|
|
22
|
+
Project-URL: Homepage, https://github.com/jbrocher/odoo-typegen
|
|
23
|
+
Project-URL: Issues, https://github.com/jbrocher/odoo-typegen/issues
|
|
24
|
+
Project-URL: Repository, https://github.com/jbrocher/odoo-typegen
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
# odoo-typegen
|
|
28
|
+
|
|
29
|
+
[](https://www.python.org/downloads/)
|
|
30
|
+
[](https://github.com/jbrocher/odoo-typegen/blob/master/LICENSE)
|
|
31
|
+
[](https://github.com/jbrocher/odoo-typegen/actions/workflows/ci.yml)
|
|
32
|
+
|
|
33
|
+
Automatic static type discovery and stub generation for Odoo projects.
|
|
34
|
+
|
|
35
|
+
odoo-typegen generates type stubs that expose addon-defined fields and methods on models retrieved
|
|
36
|
+
through the Odoo environment.
|
|
37
|
+
|
|
38
|
+
It discovers model extensions across your addons and consolidates them, so expressions such as
|
|
39
|
+
`env["crm.lead"]` evaluate to a typed models, inlcuding your own overrides. This enables accurate autocompletion and static type checking—with zero runtime impact.
|
|
40
|
+
|
|
41
|
+
#### :zap: Quickstart
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install odoo-typegen
|
|
45
|
+
odoo-typegen my_addons
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
If you have a local Odoo core copy, you can also include interfaces defined by Odoo’s base models and
|
|
49
|
+
environment:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install odoo-typegen
|
|
53
|
+
odoo-typegen my_addons --odoo-path .vendor/dooo
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## ✨ Highlights
|
|
57
|
+
|
|
58
|
+
- 🪄 **Automatic discovery:** scan existing addons without adding imports or changing
|
|
59
|
+
application code.
|
|
60
|
+
- 💡 **Typed model lookups:** resolve expressions such as `env["crm.lead"]` to the
|
|
61
|
+
generated model type.
|
|
62
|
+
- 🧩 **Model-aware stubs:** collect supported fields and methods across Odoo model
|
|
63
|
+
extensions.
|
|
64
|
+
- 🏗️ **Core overlays:** generate stubs for `Environment`, `BaseModel`, and `Model`,
|
|
65
|
+
with richer overlays when an Odoo source path is provided.
|
|
66
|
+
- 🪶 **Zero runtime impact:** generated `.pyi` files are consumed exclusively by
|
|
67
|
+
static type checkers.
|
|
68
|
+
|
|
69
|
+
## 📦 Installing
|
|
70
|
+
|
|
71
|
+
### 🐍 With pip
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install odoo-typegen
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### ❄️ With Nix
|
|
78
|
+
|
|
79
|
+
This repository includes a `flake.nix`. If you use Nix, add it to a development
|
|
80
|
+
shell like this:
|
|
81
|
+
|
|
82
|
+
```nix
|
|
83
|
+
{
|
|
84
|
+
inputs.odoo-typegen.url = "path:/home/jb/Projects/side-projects/odoo-typegen";
|
|
85
|
+
|
|
86
|
+
outputs = { nixpkgs, odoo-typegen, ... }:
|
|
87
|
+
let
|
|
88
|
+
system = "x86_64-linux";
|
|
89
|
+
pkgs = nixpkgs.legacyPackages.${system};
|
|
90
|
+
in {
|
|
91
|
+
devShells.${system}.default = pkgs.mkShell {
|
|
92
|
+
packages = [
|
|
93
|
+
odoo-typegen.packages.${system}.default
|
|
94
|
+
];
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## 🚀 Usage
|
|
101
|
+
|
|
102
|
+
### Basic usage
|
|
103
|
+
|
|
104
|
+
Pass the directory containing your Odoo addons:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
odoo-typegen ./addons
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The generated stubs are written to `./typings`. Pyright automatically discovers
|
|
111
|
+
this conventional stub directory, so its inferred Odoo types are available
|
|
112
|
+
without additional configuration.
|
|
113
|
+
|
|
114
|
+
The explicit `generate` command is equivalent:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
odoo-typegen generate ./addons
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### With an Odoo source path
|
|
121
|
+
|
|
122
|
+
Provide a local Odoo checkout to enrich the generated `Environment`,
|
|
123
|
+
`BaseModel`, and `Model` stubs with interfaces discovered from Odoo's source:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
odoo-typegen ./addons --odoo-path ./.vendor/odoo
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Type-checker integration
|
|
130
|
+
|
|
131
|
+
#### Pyright
|
|
132
|
+
|
|
133
|
+
With the default output directory, simply generate the stubs and run Pyright:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
odoo-typegen ./addons
|
|
137
|
+
pyright
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
For a custom output directory, pass `--output-path` and set the same directory
|
|
141
|
+
as `stubPath` in `pyrightconfig.json`:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
odoo-typegen ./addons --output-path ./generated-stubs
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"stubPath": "./generated-stubs"
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### mypy
|
|
154
|
+
|
|
155
|
+
mypy does not automatically discover `./typings`. Point `mypy_path` at the
|
|
156
|
+
generated stubs in `pyproject.toml`:
|
|
157
|
+
|
|
158
|
+
```toml
|
|
159
|
+
[tool.mypy]
|
|
160
|
+
mypy_path = "./typings"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Then generate the stubs and check your addons:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
odoo-typegen ./addons
|
|
167
|
+
mypy ./addons
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
To use a custom location, pass `--output-path` and update `mypy_path` to match.
|
|
171
|
+
For a one-off run, you can set it without changing your configuration:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
odoo-typegen ./addons --output-path ./generated-stubs
|
|
175
|
+
MYPYPATH=./generated-stubs mypy ./addons
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## ⚙️ How it works
|
|
179
|
+
|
|
180
|
+
Suppose you have a few addons that add some methods and attributes to the `crm.lead` model. For instance the first addon add a custom source field:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# addons/crm_base_extension/models/crm_lead.py
|
|
184
|
+
from odoo import fields, models
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class CrmLead(models.Model):
|
|
188
|
+
_inherit = "crm.lead"
|
|
189
|
+
|
|
190
|
+
my_custom_source = fields.Char()
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
The second addon adds a priority code and a helper method:
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
# addons/crm_followup_extension/models/crm_lead.py
|
|
198
|
+
from odoo import fields, models
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class CrmLead(models.Model):
|
|
202
|
+
_inherit = "crm.lead"
|
|
203
|
+
|
|
204
|
+
priority = fields.Integer()
|
|
205
|
+
|
|
206
|
+
def is_high_priorty(self) -> bool:
|
|
207
|
+
return self.priority > 3
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
odoo-typegen follows both extensions and consolidates their members into one
|
|
211
|
+
stub for `crm.lead`:
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
# typings/crm/lead.pyi
|
|
215
|
+
# Generated by odoo-typegen.
|
|
216
|
+
from odoo.models import Model
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class CrmLead(Model):
|
|
220
|
+
my_custom_source: str
|
|
221
|
+
priority: int
|
|
222
|
+
def is_high_priorty(self) -> bool: ...
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
These models are then used in Stubs for Environment, models.Model, and models.BaseModel, which is how
|
|
226
|
+
the typing are automatically "injected" in your poject. This is how `self.env["crm.lead"]` will actually
|
|
227
|
+
be infered as implementing CrmLead.
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
# ./typings/odoo/orm/environments.pyi
|
|
231
|
+
import typing
|
|
232
|
+
from crm.lead import CrmLead
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class Environment:
|
|
236
|
+
@typing.overload
|
|
237
|
+
def __getitem__(self, model_name: typing.Literal["crm.lead"]) -> CrmLead: ...
|
|
238
|
+
@typing.overload
|
|
239
|
+
def __getitem__(self, model_name: str) -> typing.Any: ...
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
# ./typings/odoo/orm/models.pyi
|
|
244
|
+
from odoo.orm.environments import Environment
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class BaseModel:
|
|
248
|
+
env: Environment
|
|
249
|
+
|
|
250
|
+
class Model(BaseModel):
|
|
251
|
+
...
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## 🗺️ Roadmap
|
|
255
|
+
|
|
256
|
+
- 👀 Add a `--watch` option to regenerate types automatically.
|
|
257
|
+
- Include Odoo Core models overrides
|
|
258
|
+
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# odoo-typegen
|
|
2
|
+
|
|
3
|
+
[](https://www.python.org/downloads/)
|
|
4
|
+
[](https://github.com/jbrocher/odoo-typegen/blob/master/LICENSE)
|
|
5
|
+
[](https://github.com/jbrocher/odoo-typegen/actions/workflows/ci.yml)
|
|
6
|
+
|
|
7
|
+
Automatic static type discovery and stub generation for Odoo projects.
|
|
8
|
+
|
|
9
|
+
odoo-typegen generates type stubs that expose addon-defined fields and methods on models retrieved
|
|
10
|
+
through the Odoo environment.
|
|
11
|
+
|
|
12
|
+
It discovers model extensions across your addons and consolidates them, so expressions such as
|
|
13
|
+
`env["crm.lead"]` evaluate to a typed models, inlcuding your own overrides. This enables accurate autocompletion and static type checking—with zero runtime impact.
|
|
14
|
+
|
|
15
|
+
#### :zap: Quickstart
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install odoo-typegen
|
|
19
|
+
odoo-typegen my_addons
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you have a local Odoo core copy, you can also include interfaces defined by Odoo’s base models and
|
|
23
|
+
environment:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install odoo-typegen
|
|
27
|
+
odoo-typegen my_addons --odoo-path .vendor/dooo
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ✨ Highlights
|
|
31
|
+
|
|
32
|
+
- 🪄 **Automatic discovery:** scan existing addons without adding imports or changing
|
|
33
|
+
application code.
|
|
34
|
+
- 💡 **Typed model lookups:** resolve expressions such as `env["crm.lead"]` to the
|
|
35
|
+
generated model type.
|
|
36
|
+
- 🧩 **Model-aware stubs:** collect supported fields and methods across Odoo model
|
|
37
|
+
extensions.
|
|
38
|
+
- 🏗️ **Core overlays:** generate stubs for `Environment`, `BaseModel`, and `Model`,
|
|
39
|
+
with richer overlays when an Odoo source path is provided.
|
|
40
|
+
- 🪶 **Zero runtime impact:** generated `.pyi` files are consumed exclusively by
|
|
41
|
+
static type checkers.
|
|
42
|
+
|
|
43
|
+
## 📦 Installing
|
|
44
|
+
|
|
45
|
+
### 🐍 With pip
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install odoo-typegen
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### ❄️ With Nix
|
|
52
|
+
|
|
53
|
+
This repository includes a `flake.nix`. If you use Nix, add it to a development
|
|
54
|
+
shell like this:
|
|
55
|
+
|
|
56
|
+
```nix
|
|
57
|
+
{
|
|
58
|
+
inputs.odoo-typegen.url = "path:/home/jb/Projects/side-projects/odoo-typegen";
|
|
59
|
+
|
|
60
|
+
outputs = { nixpkgs, odoo-typegen, ... }:
|
|
61
|
+
let
|
|
62
|
+
system = "x86_64-linux";
|
|
63
|
+
pkgs = nixpkgs.legacyPackages.${system};
|
|
64
|
+
in {
|
|
65
|
+
devShells.${system}.default = pkgs.mkShell {
|
|
66
|
+
packages = [
|
|
67
|
+
odoo-typegen.packages.${system}.default
|
|
68
|
+
];
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 🚀 Usage
|
|
75
|
+
|
|
76
|
+
### Basic usage
|
|
77
|
+
|
|
78
|
+
Pass the directory containing your Odoo addons:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
odoo-typegen ./addons
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The generated stubs are written to `./typings`. Pyright automatically discovers
|
|
85
|
+
this conventional stub directory, so its inferred Odoo types are available
|
|
86
|
+
without additional configuration.
|
|
87
|
+
|
|
88
|
+
The explicit `generate` command is equivalent:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
odoo-typegen generate ./addons
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### With an Odoo source path
|
|
95
|
+
|
|
96
|
+
Provide a local Odoo checkout to enrich the generated `Environment`,
|
|
97
|
+
`BaseModel`, and `Model` stubs with interfaces discovered from Odoo's source:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
odoo-typegen ./addons --odoo-path ./.vendor/odoo
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Type-checker integration
|
|
104
|
+
|
|
105
|
+
#### Pyright
|
|
106
|
+
|
|
107
|
+
With the default output directory, simply generate the stubs and run Pyright:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
odoo-typegen ./addons
|
|
111
|
+
pyright
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
For a custom output directory, pass `--output-path` and set the same directory
|
|
115
|
+
as `stubPath` in `pyrightconfig.json`:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
odoo-typegen ./addons --output-path ./generated-stubs
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"stubPath": "./generated-stubs"
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### mypy
|
|
128
|
+
|
|
129
|
+
mypy does not automatically discover `./typings`. Point `mypy_path` at the
|
|
130
|
+
generated stubs in `pyproject.toml`:
|
|
131
|
+
|
|
132
|
+
```toml
|
|
133
|
+
[tool.mypy]
|
|
134
|
+
mypy_path = "./typings"
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Then generate the stubs and check your addons:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
odoo-typegen ./addons
|
|
141
|
+
mypy ./addons
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
To use a custom location, pass `--output-path` and update `mypy_path` to match.
|
|
145
|
+
For a one-off run, you can set it without changing your configuration:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
odoo-typegen ./addons --output-path ./generated-stubs
|
|
149
|
+
MYPYPATH=./generated-stubs mypy ./addons
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## ⚙️ How it works
|
|
153
|
+
|
|
154
|
+
Suppose you have a few addons that add some methods and attributes to the `crm.lead` model. For instance the first addon add a custom source field:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# addons/crm_base_extension/models/crm_lead.py
|
|
158
|
+
from odoo import fields, models
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class CrmLead(models.Model):
|
|
162
|
+
_inherit = "crm.lead"
|
|
163
|
+
|
|
164
|
+
my_custom_source = fields.Char()
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The second addon adds a priority code and a helper method:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
# addons/crm_followup_extension/models/crm_lead.py
|
|
172
|
+
from odoo import fields, models
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class CrmLead(models.Model):
|
|
176
|
+
_inherit = "crm.lead"
|
|
177
|
+
|
|
178
|
+
priority = fields.Integer()
|
|
179
|
+
|
|
180
|
+
def is_high_priorty(self) -> bool:
|
|
181
|
+
return self.priority > 3
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
odoo-typegen follows both extensions and consolidates their members into one
|
|
185
|
+
stub for `crm.lead`:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# typings/crm/lead.pyi
|
|
189
|
+
# Generated by odoo-typegen.
|
|
190
|
+
from odoo.models import Model
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class CrmLead(Model):
|
|
194
|
+
my_custom_source: str
|
|
195
|
+
priority: int
|
|
196
|
+
def is_high_priorty(self) -> bool: ...
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
These models are then used in Stubs for Environment, models.Model, and models.BaseModel, which is how
|
|
200
|
+
the typing are automatically "injected" in your poject. This is how `self.env["crm.lead"]` will actually
|
|
201
|
+
be infered as implementing CrmLead.
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
# ./typings/odoo/orm/environments.pyi
|
|
205
|
+
import typing
|
|
206
|
+
from crm.lead import CrmLead
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class Environment:
|
|
210
|
+
@typing.overload
|
|
211
|
+
def __getitem__(self, model_name: typing.Literal["crm.lead"]) -> CrmLead: ...
|
|
212
|
+
@typing.overload
|
|
213
|
+
def __getitem__(self, model_name: str) -> typing.Any: ...
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# ./typings/odoo/orm/models.pyi
|
|
218
|
+
from odoo.orm.environments import Environment
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class BaseModel:
|
|
222
|
+
env: Environment
|
|
223
|
+
|
|
224
|
+
class Model(BaseModel):
|
|
225
|
+
...
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## 🗺️ Roadmap
|
|
229
|
+
|
|
230
|
+
- 👀 Add a `--watch` option to regenerate types automatically.
|
|
231
|
+
- Include Odoo Core models overrides
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "odoo-typegen"
|
|
3
|
+
version = "0.1.2"
|
|
4
|
+
description = "Static type discovery and stub generation for Odoo addons."
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "jb",email = "jeanb.rocher@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = {text = "MIT"}
|
|
10
|
+
requires-python = ">=3.10,<3.14"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"pydantic (>=2.11.7,<3.0.0)",
|
|
13
|
+
"astroid (>=3.3.10,<5.0.0)",
|
|
14
|
+
"cyclopts (>=3.22.5,<5.0.0)"
|
|
15
|
+
]
|
|
16
|
+
keywords = ["odoo", "typing", "stubs", "pyright"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://github.com/jbrocher/odoo-typegen"
|
|
31
|
+
Repository = "https://github.com/jbrocher/odoo-typegen"
|
|
32
|
+
Issues = "https://github.com/jbrocher/odoo-typegen/issues"
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
odoo-typegen = "odoo_typegen.cli:main"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
[build-system]
|
|
39
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
40
|
+
build-backend = "poetry.core.masonry.api"
|
|
41
|
+
|
|
42
|
+
[tool.poetry]
|
|
43
|
+
packages = [
|
|
44
|
+
{ include = "odoo_typegen", from = "src" },
|
|
45
|
+
]
|
|
46
|
+
exclude = [
|
|
47
|
+
"src/odoo_typegen/**/tests/**",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
[tool.poetry.group.dev.dependencies]
|
|
51
|
+
pytest = "^9.1.1"
|
|
52
|
+
ruff = "^0.12.10"
|
|
53
|
+
twine = "^7.0.0"
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
addopts = "-m 'not integration'"
|
|
57
|
+
markers = [
|
|
58
|
+
"integration: tests that use local integration fixtures and are skipped by default",
|
|
59
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from cyclopts import App
|
|
4
|
+
|
|
5
|
+
from odoo_typegen.compiler.compiler import Compiler
|
|
6
|
+
from odoo_typegen.compiler.environment_compiler import EnvironmentCompiler
|
|
7
|
+
from odoo_typegen.compiler.model_compiler import ModelCompiler
|
|
8
|
+
from odoo_typegen.emitter.type_emitter import TypeEmitter
|
|
9
|
+
from odoo_typegen.registry.registry_service import RegistryService
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
app = App()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _generate(
|
|
16
|
+
addon_path: Path,
|
|
17
|
+
output_path: Path,
|
|
18
|
+
odoo_path: Path | None = None,
|
|
19
|
+
) -> tuple[Path, ...]:
|
|
20
|
+
registry = RegistryService(addon_path=addon_path).build()
|
|
21
|
+
models = Compiler().compile(registry)
|
|
22
|
+
environment = EnvironmentCompiler(odoo_path=odoo_path).compile(models)
|
|
23
|
+
core_models = ModelCompiler(odoo_path=odoo_path).compile()
|
|
24
|
+
emitter = TypeEmitter(output_path=output_path)
|
|
25
|
+
|
|
26
|
+
emitted_files = (
|
|
27
|
+
*emitter.emit(models),
|
|
28
|
+
*emitter.emit_environment(environment),
|
|
29
|
+
*emitter.emit_core_models(core_models),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
for emitted_file in emitted_files:
|
|
33
|
+
print(emitted_file)
|
|
34
|
+
|
|
35
|
+
return emitted_files
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@app.default
|
|
39
|
+
def default(
|
|
40
|
+
addon_path: Path,
|
|
41
|
+
output_path: Path = Path("typings"),
|
|
42
|
+
*,
|
|
43
|
+
odoo_path: Path | None = None,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Generate Python stub files for Odoo addons.
|
|
46
|
+
|
|
47
|
+
Parameters
|
|
48
|
+
----------
|
|
49
|
+
addon_path: Path
|
|
50
|
+
Directory containing Odoo addon directories.
|
|
51
|
+
output_path: Path
|
|
52
|
+
Directory where generated .pyi files should be written. Defaults to
|
|
53
|
+
./typings, which Pyright discovers automatically.
|
|
54
|
+
odoo_path: Path | None
|
|
55
|
+
Optional path to a local Odoo checkout used to overlay core stubs.
|
|
56
|
+
"""
|
|
57
|
+
_generate(addon_path, output_path, odoo_path)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@app.command
|
|
61
|
+
def generate(
|
|
62
|
+
addon_path: Path,
|
|
63
|
+
output_path: Path = Path("typings"),
|
|
64
|
+
*,
|
|
65
|
+
odoo_path: Path | None = None,
|
|
66
|
+
) -> None:
|
|
67
|
+
"""Generate Python stub files for Odoo addons.
|
|
68
|
+
|
|
69
|
+
Parameters
|
|
70
|
+
----------
|
|
71
|
+
addon_path: Path
|
|
72
|
+
Directory containing Odoo addon directories.
|
|
73
|
+
output_path: Path
|
|
74
|
+
Directory where generated .pyi files should be written. Defaults to
|
|
75
|
+
./typings, which Pyright discovers automatically.
|
|
76
|
+
odoo_path: Path | None
|
|
77
|
+
Optional path to a local Odoo checkout used to overlay core stubs.
|
|
78
|
+
"""
|
|
79
|
+
_generate(addon_path, output_path, odoo_path)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def main() -> None:
|
|
83
|
+
app()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
|
File without changes
|