From b039f790ca9a23b89c6cd18aacf0d71ec9cde339 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 22:44:48 +0800 Subject: [PATCH 1/3] feat: keep only the lead above the table for an intro without a pick list An intro without a "How to choose" list, as a one-project category has no picks to compare, rendered all of its guide paragraphs above the table, pushing the table down. It now shows the lead above the table and moves the rest into the guide. Co-Authored-By: Claude --- website/build.py | 5 +++-- website/tests/test_build.py | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/website/build.py b/website/build.py index 5078421c..9085920a 100755 --- a/website/build.py +++ b/website/build.py @@ -351,7 +351,8 @@ def load_category_intro(path: Path, entry_names: Sequence[str] = ()) -> tuple[st Returns the part shown above the table, the guide shown below it, and the first paragraph as plain text for the meta description and as HTML for - group pages. A file without the list keeps everything above the table. + group pages. A file without the list, like a one-project category's, + keeps only its lead above the table. Returns empty strings if the category has no intro file. """ if not path.exists(): @@ -364,7 +365,7 @@ def load_category_intro(path: Path, entry_names: Sequence[str] = ()) -> tuple[st child.attrSet("target", "_blank") child.attrSet("rel", "noopener") lead = next(node for node in SyntaxTreeNode(tokens).children if node.type == "paragraph") - split_at = len(tokens) + split_at = next(j for j, token in enumerate(tokens) if token.type == "paragraph_close" and token.level == 0) + 1 for i, token in enumerate(tokens): if token.type == "inline" and token.level == 1 and token.content == "How to choose:" and i + 2 < len(tokens) and tokens[i + 2].type == "bullet_list_open": split_at = next(j for j in range(i + 3, len(tokens)) if tokens[j].type == "bullet_list_close" and tokens[j].level == 0) + 1 diff --git a/website/tests/test_build.py b/website/tests/test_build.py index e567c84b..5b3cd15a 100644 --- a/website/tests/test_build.py +++ b/website/tests/test_build.py @@ -1673,12 +1673,12 @@ class TestLoadCategoryIntro: assert lead == "Use w1 for most apps." assert lead_html == "

Use w1 for most apps.

\n" - def test_keeps_everything_above_table_without_how_to_choose_list(self, tmp_path): + def test_splits_after_lead_without_how_to_choose_list(self, tmp_path): path = tmp_path / "widgets.md" path.write_text("Use w1.\n\n- Small apps: w1\n\nConfigure w1 once.\n", encoding="utf-8") intro_html, guide_html, _, _ = load_category_intro(path) - assert "Configure w1 once." in intro_html - assert guide_html == "" + assert intro_html == "

Use w1.

\n" + assert guide_html == "\n

Configure w1 once.

\n" def test_returns_empty_strings_without_intro_file(self, tmp_path): assert load_category_intro(tmp_path / "missing.md") == ("", "", "", "") From e1875b6b2b86e3bd98d400d10ced1e0bbee7deb0 Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 22:57:07 +0800 Subject: [PATCH 2/3] docs: rewrite ERP category intro The ERP category lists one project, Odoo, but the intro's "How to choose" list compared Odoo editions and hosting options as if they were picks. Co-Authored-By: Claude --- website/data/category_intros/erp.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/website/data/category_intros/erp.md b/website/data/category_intros/erp.md index 390c2921..80f63ec6 100644 --- a/website/data/category_intros/erp.md +++ b/website/data/category_intros/erp.md @@ -1,19 +1,13 @@ -Out of the box, Odoo's CRM, eCommerce, and accounting apps run alone or combine into a full Python ERP. Anything they lack, you add as a module. +Install several Odoo apps, like CRM, accounting, and inventory, and they combine into an open source Python ERP that your own modules extend. -How to choose: +In Odoo, [everything starts and ends with modules](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#odoo-modules): each app you install is one, and so is each change you make. [Odoo Community is the free and open source edition](https://www.odoo.com/documentation/latest/administration.html#editions). Enterprise is [extra modules installed on top of Community](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#odoo-editions), and its license [allows running it only with an Enterprise subscription](https://www.odoo.com/documentation/latest/legal/licenses.html#odoo-enterprise-license). -- Trying Odoo, or customizing it without code: Odoo Online -- Writing your own modules: a source install -- Hosting your own modules in the cloud: Odoo.sh -- Free and open source: Odoo Community -- More features, with support and upgrades: Odoo Enterprise +Where you host Odoo decides whether your own Python code runs on it. [Odoo Online doesn't run custom modules](https://www.odoo.com/documentation/latest/administration/odoo_online.html), but [Studio customizes Odoo there without code](https://www.odoo.com/documentation/latest/applications/studio.html). Odoo.sh, Odoo's official cloud platform, [deploys your modules from a branch of your GitHub repository](https://www.odoo.com/documentation/latest/administration/odoo_sh/getting_started/create.html#push-modules-in-production). Your own server runs whatever modules its addons path points to. -Everything in Odoo starts and ends with modules, and [the main user-facing ones are flagged as Apps](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#odoo-modules). Odoo Enterprise is [extra modules installed on top of Community](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#odoo-editions). [Community is free and open source under the LGPL](https://www.odoo.com/documentation/latest/administration.html#editions). Enterprise is shared source, and its license [ties running it to an Enterprise subscription](https://www.odoo.com/documentation/latest/legal/licenses.html). +To develop modules, Odoo's developer docs prefer [a source install](https://www.odoo.com/documentation/latest/developer/tutorials/setup_guide.html), which runs Odoo from its source code. Keep your modules in a directory of their own, and [start the server with `odoo-bin`](https://www.odoo.com/documentation/latest/administration/on_premise/source.html#install-source-running-odoo), adding that directory to `--addons-path`. Then work through [Server framework 101](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101.html), which builds one module from scratch. -[Odoo Online](https://www.odoo.com/documentation/latest/administration/odoo_online.html) runs in your browser with nothing to install, and handles customizations that need no code. Your own modules need Odoo.sh or your own server. Odoo.sh is Odoo's official cloud platform, and it [builds your modules from a GitHub repository](https://www.odoo.com/documentation/latest/administration/odoo_sh/create_module.html). +A module is a Python package whose `__manifest__.py` [names the module and the modules it depends on](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/02_newapp.html#prepare-the-addon-directory). Business objects are [Python classes extending `Model`](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/03_basicmodel.html#object-relational-mapping), whose fields the ORM maps to database columns. Give each model access rights, since [without them, no user can access its data](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/04_securityintro.html#access-rights). -To develop modules, Odoo's developer docs prefer [a source install](https://www.odoo.com/documentation/latest/developer/tutorials/setup_guide.html), which runs Odoo straight from its code. Odoo's logic is [written in Python, and it stores data only in PostgreSQL](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#multitier-application). Keep your modules in a directory of their own, and [start the server with `odoo-bin`](https://www.odoo.com/documentation/latest/administration/on_premise/source.html#running-odoo), adding that directory to `--addons-path`. Then work through [Server framework 101](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101.html), which builds one module chapter by chapter. +To change an app Odoo ships, extend it from your own module instead of editing its code. [Model inheritance](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/12_inheritance.html#model-inheritance) adds fields and overrides methods on a model another module defines, and [view inheritance](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/12_inheritance.html#view-inheritance) applies your extension views on top of the originals. When a feature joins two apps, put it in [a link module](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/13_other_module.html#link-module), so each app still installs on its own. -A module can [add new business logic or change what's already there](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/01_architecture.html#odoo-modules). To change a standard model, extend it from your own module: [model inheritance](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/12_inheritance.html#model-inheritance) adds fields and overrides methods on a model another module defines. Screens work the same way: [view inheritance](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/12_inheritance.html#view-inheritance) applies your extension views on top of the originals instead of overwriting them. - -Before you write a module, [check whether Odoo already covers the case](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/02_newapp.html). A database with custom modules [can't be upgraded until they're ready for the new version](https://www.odoo.com/documentation/latest/administration/upgrade.html), so [cut what duplicates the standard modules](https://www.odoo.com/documentation/latest/developer/howtos/upgrade_custom_db.html#step-1-stop-the-developments). +Before you write a module, [check whether Odoo already covers the case](https://www.odoo.com/documentation/latest/developer/tutorials/server_framework_101/02_newapp.html#the-real-estate-advertisement-module). A database with custom modules [can't be upgraded until they're ready for the new version](https://www.odoo.com/documentation/latest/administration/upgrade.html), so each module you skip is one less to port. From b58c1ff4a15c1bbf2b8a3a1d0a3adcee69c8cffa Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 21 Oct 2026 22:56:17 +0800 Subject: [PATCH 3/3] refactor: drop Odoo pick aliases the ERP intro no longer uses Co-Authored-By: Claude --- website/build.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/website/build.py b/website/build.py index 9085920a..2185a9c8 100755 --- a/website/build.py +++ b/website/build.py @@ -58,9 +58,6 @@ PICK_ALIASES = { "Jupyter Notebook": "notebook", "Material for MkDocs": "mkdocs-material", "MCP Python SDK": "mcp", - "Odoo Community": "odoo", - "Odoo Enterprise": "odoo", - "Odoo Online": "odoo", "OpenAI Agents SDK": "openai-agents", "OpenCV": "opencv-python", "Playwright": "playwright-python",