| type | reference | ||||
|---|---|---|---|---|---|
| title | Support matrix | ||||
| description | What odoo_dwg supports — hosts, Python per Odoo version, PostgreSQL — with the source behind every bound and how to re-verify it. | ||||
| tags |
|
||||
| audience |
|
||||
| updated | 2026-09-20 |
This page is the authority on what the tool supports. The same facts live in code as
ODOO_SUPPORT / SUPPORTED_HOSTS in odoo_dwg/models.py, which every surface —
provision check, workspace generation, migration environments, the generated per-workspace README — reads
from rather than restating. Change a bound there and here together; nowhere else states one.
Every bound below carries its evidence tier, because only one Odoo version states a Python maximum outright:
| Tier | Meaning |
|---|---|
official |
Odoo or the distribution states it outright. |
derived |
Deduced from an official artifact — the newest interpreter bucket a branch's own requirements.txt declares, read through the distribution its comment names. |
untested |
No source states it and this project has not validated it. Treated as "no bound", never as "works". |
The tool never presents a derived or untested bound as an Odoo requirement: it prints the tier alongside
the value.
One host: Ubuntu 24.04 LTS, the reference box every end-to-end acceptance runs on. Hosts that were declared
but never run were dropped rather than implied: Debian first, then Ubuntu 22.04 (2026-09-19). provision check
reports any other host as unsupported and still completes; provision apply refuses before running anything.
| Host | Codename | System python3 |
PostgreSQL |
|---|---|---|---|
| Ubuntu 24.04 LTS | noble | 3.12 | 16 |
Source: packages.ubuntu.com/noble/python3,
/noble/postgresql.
The tool's own Python floor is 3.12, the supported host's system Python, and it matches
requires-python = ">=3.12" in pyproject.toml (a unit test asserts the two agree).
| Odoo | Python min | tier | Python max | tier | Recommended | PostgreSQL min | tier |
|---|---|---|---|---|---|---|---|
| 12.0 | 3.5 | official | — | untested | 3.8 | — | untested |
| 13.0 | 3.6 | official | — | untested | 3.8 | — | untested |
| 14.0 | 3.7 | official¹ | 3.10 | derived | 3.8 | 12.0 | official |
| 15.0 | 3.7 | official | 3.12 | official | 3.8 | 12.0 | official |
| 16.0 | 3.7 | official | 3.12 | official | 3.10 | 12.0 | official |
| 17.0 | 3.10 | official | 3.14 | official | 3.10 | 12.0 | official |
| 18.0 | 3.10 | official | 3.14 | official | 3.12 | 12.0 | official |
| 19.0 | 3.10 | official | 3.14 | official | 3.12 | 13.0 | official |
¹ Odoo 14's sources disagree with its documentation — see Known divergences.
Recommended is not the maximum. The recommended column is what this project has actually built and run
(measured on the reference box, where uv's installable floor is 3.8); the range is what Odoo declares. That
is why Odoo 15 recommends 3.8 although it tolerates 3.12. The recommendation is a default: every flow that
builds an environment lets the operator choose another interpreter, and says so when a choice falls outside
the range.
An unstated maximum is not a green light. Odoo 12 and 13 state no ceiling, so no interpreter is ever
outside their range — but that is absence of evidence: on 3.12 their pinned gevent does not build (measured
2026-09-19). A workspace therefore uses the host python3 for them only when it is no newer than the
recommendation, and otherwise defaults to the recommended uv interpreter.
| Odoo | Quote | Source |
|---|---|---|
| 12.0 | "Odoo requires Python 3.5 or later to run." · "Download and install the latest version of PostgreSQL." (no floor given) | 12.0 install |
| 13.0 | python_requires='>=3.6' — its install page contains no requirements text at all |
setup.py@13.0 |
| 14.0 | "Odoo requires Python 3.7 or later to run." · "supported versions: 12.0 or above" | 14.0 source install |
| 15.0 | "Odoo requires Python 3.7 or later to run." · "supported versions: 12.0 or above" | 15.0 source install |
| 16.0 | "Odoo requires Python 3.7 or later to run." · "supported versions: 12.0 or above" | 16.0 source install |
| 17.0 | "Odoo requires Python 3.10 or later to run." · "Changed in version 17: Minimum requirement updated from Python 3.7 to Python 3.10." | 17.0 source install |
| 18.0 | "Odoo requires Python 3.10 or later to run." · "supported versions: 12.0 or above" | 18.0 source install |
| 15.0 | MIN_PY_VERSION = (3, 7) · MAX_PY_VERSION = (3, 12) |
odoo/__init__.py@15.0 |
| 16.0 | MIN_PY_VERSION = (3, 7) · MAX_PY_VERSION = (3, 12) |
odoo/__init__.py@16.0 |
| 17.0 | MIN_PY_VERSION = (3, 10) · MAX_PY_VERSION = (3, 14) |
odoo/__init__.py@17.0 |
| 18.0 | MIN_PY_VERSION = (3, 10) · MAX_PY_VERSION = (3, 14) |
odoo/__init__.py@18.0 |
| 19.0 | MIN_PY_VERSION = (3, 10) · MAX_PY_VERSION = (3, 14) |
odoo/release.py@19.0 |
| 19.0 | "Changed in version 19: Minimum requirement updated from PostgreSQL 12 to PostgreSQL 13." · "supported versions: 13.0 or above" | 19.0 source install |
No Odoo documentation page states a maximum Python, but the code does: 15.0–18.0 declare MAX_PY_VERSION in
odoo/__init__.py, 19.0 in odoo/release.py. Above it Odoo starts and logs "Python X is not officially
supported" (odoo/cli/server.py). Odoo 14 declares none. For 14 the maximum comes from its requirements.txt,
which splits its pins into buckets by python_version and names the target distribution in the comment:
the newest such bucket is the newest interpreter that branch is maintained for. The other rows show the same
reading for comparison:
| Odoo | Newest bucket, verbatim | Distribution | ⇒ max |
|---|---|---|---|
| 14.0 | gevent==21.8.0 ; python_version > '3.9' # (Jammy) |
Ubuntu 22.04 | 3.10 |
| 15.0 | gevent==24.2.1 ; sys_platform != 'win32' and python_version >= '3.12' # (Noble) |
Ubuntu 24.04 | 3.12 |
| 16.0 | PyPDF==5.4.0 ; python_version >= '3.13' # (Trixie) |
Debian 13 | 3.13 |
| 17.0 | greenlet==3.3.2 ; sys_platform != 'win32' and python_version >= '3.14' # (Resolute) |
Ubuntu 26.04 | 3.14 |
| 18.0 | same Resolute bucket | Ubuntu 26.04 | 3.14 |
| 19.0 | same Resolute bucket | Ubuntu 26.04 | 3.14 |
How far to trust this derivation: it agrees with the declared value for 15, 17, 18 and 19. It disagrees
for 16, whose requirements gained a Debian 13 (Python 3.13) bucket while MAX_PY_VERSION stayed (3, 12). The
declared value is the one carried, so the derivation is only used for 14, which declares nothing. An earlier
version of this page read MAX_PY_VERSION from release.py only. 15–18 therefore looked undeclared, and 16
was carried as 3.13, derived.
Odoo 12 and 13 have open-ended >= '3.7' / >= '3.8' buckets that name no distribution, so they get no
ceiling — tier untested. Odoo 13 is nevertheless known to run on uv's 3.8 floor: its requirements
install there and a 12 → 13 migration completes (measured 2026-09-17), which is what lets every step run
natively. That is a floor result, not a ceiling: nothing says where the branch stops working, so the bound
stays untested. Odoo 12 is never executed by a chain at all.
- Odoo 14: documentation 3.7 vs
setup.py>=3.6. The matrix carries the stricter documented floor, 3.7. The verification script knows both readings and reports the disagreement rather than treating it as drift. - Community reports are not used as bounds. The most-cited threads for "Odoo 16 cannot run on Python
3.11" and "Odoo 17 fails on Python 3.12" turn out to be a macOS
psycopg2linking error (no LC_RPATH's found) and an uninitialised database — neither is an interpreter ceiling, and the repository data contradicts the conclusion both reach. They are useful as symptom references, nothing more.
python tools/verify_support_matrix.py # every version and the supported host
python tools/verify_support_matrix.py 18.0 19.0 # only these versionsThe script re-derives every bound from the sources below and exits non-zero on drift, naming the version,
the fact, both values and the source URL. It never edits the declared matrix: fixing drift means editing
odoo_dwg/models.py and this page together. It is stdlib-only, lives outside the package
(odoo_dwg never imports it) and outside the unit suite, like every tools/verify_*.py. What each of those
needs is listed once, in CONTRIBUTING.md.
| Fact | Primary | Secondary |
|---|---|---|
| Python minimum | raw.githubusercontent.com/odoo/odoo/<v>/odoo/release.py (19.0) or .../odoo/__init__.py (15.0–18.0) → MIN_PY_VERSION, then .../setup.py → python_requires |
the version's source-install page |
| Python maximum | .../odoo/release.py (19.0) or .../odoo/__init__.py (15.0–18.0) → MAX_PY_VERSION |
.../requirements.txt → newest python_version bucket + the distribution its comment names (14.0) |
| PostgreSQL minimum | the version's source-install page → "supported versions: N.0 or above" | — |
Host python3 / PostgreSQL |
packages.ubuntu.com/<codename>/python3 and /postgresql |
— |
The repository is primary, the manual secondary. The manual states no maxima, and it has a hole exactly where you would not look for one (13.0).
The path changed twice across the supported range, so it must be resolved per version rather than assumed
(odoo_docs_url() in models.py does this):
| Versions | Path |
|---|---|
| 12.0, 13.0 | /documentation/<v>/setup/install.html |
| 14.0 | /documentation/<v>/administration/install/source.html |
| 15.0 – 19.0 | /documentation/<v>/administration/on_premise/source.html |
- A summarising web fetcher returns empty content for every pre-17 documentation page while reporting success. Retrieve the HTML directly and strip the tags locally.
- The Odoo 13.0 install page is a table-of-contents stub with no requirements text, so a
documentation-only method has a silent hole. Use
setup.pyfor that version. - Splitting text on
.shreds "Python 3.10". MatchPython 3\.\d+andsupported versions?: \d+\.\d+as patterns instead. - Codename → Python must come from the distribution, not from memory. Jammy 3.10, Noble 3.12,
Resolute 3.14 are all read from
packages.ubuntu.com; Trixie (Debian 13) is 3.13. >=and<buckets are not symmetric. Only an open-ended upper bucket (>=/>) says what a branch targets; a< '3.12'bucket is the older half of a split and means nothing about the ceiling.
provision checkreports the host release against the supported list, the installed PostgreSQL server against the floor of the versions in play, the hostpython3, and which interpretersuvcan provide.provision applyrefuses any host outside the supported releases, before assembling a single command.- Workspace generation builds each instance's venv with the host
python3when it is inside that version's range; when it is not, it says so — naming the range, the detected version and the evidence tier — and offers a matchinguv-provisioned interpreter instead (uv venv --seed, so the venv still haspipand everything downstream is unchanged). - Migration environments take each step's interpreter from the recommendation, and let the operator pin
any step to a specific Python. A pinned step's requirements repair follows the interpreter actually in use.
Every step runs natively on a
uvinterpreter, including Odoo 13, so no chain needs a container runtime.
provisioning.md— the host readiness table and whatapplyinstalls.- The migration environment — chains, interpreters and the two OpenUpgrade layouts.
- Profile fields — the workspace profile.
roadmap.md— the open validation items this page depends on.