This is an automated email from the ASF dual-hosted git repository.
400Ping pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/main by this push:
new 69568a017 [Feature] Generate Python API docs from module discovery
(#1392)
69568a017 is described below
commit 69568a0173f8973f6b74ef7706aa3b5755bf98ae
Author: Vic Wen <[email protected]>
AuthorDate: Tue Jun 16 11:05:08 2026 +0800
[Feature] Generate Python API docs from module discovery (#1392)
* feat(website): generate Python API docs from module discovery
Refs #1347
* docs: simplify QDP API doc generation
* chore: align script coding style
* ci: install uv for website builds
---
.github/workflows/website-build.yml | 3 ++
.github/workflows/website.yml | 3 ++
CONTRIBUTING.md | 14 ++++++++++
docs/api/qumat_qdp.yml | 22 ++++-----------
website/docusaurus.config.ts | 2 +-
website/scripts/sync-docs.js | 56 +++++++++++++++++++++++++++++++++++++
website/sidebars.ts | 10 +++++++
7 files changed, 93 insertions(+), 17 deletions(-)
diff --git a/.github/workflows/website-build.yml
b/.github/workflows/website-build.yml
index 5a9fb89a4..e6764eb43 100644
--- a/.github/workflows/website-build.yml
+++ b/.github/workflows/website-build.yml
@@ -38,6 +38,9 @@ jobs:
cache: 'npm'
cache-dependency-path: website/package-lock.json
+ - name: Install uv
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b #
v8.1.0
+
- name: Install dependencies
working-directory: website
run: npm ci
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index d6a668970..fde77036b 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -42,6 +42,9 @@ jobs:
cache: 'npm'
cache-dependency-path: website/package-lock.json
+ - name: Install uv
+ uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b #
v8.1.0
+
- name: Install dependencies
working-directory: website
run: npm ci
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 88f069362..d85f09a38 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,6 +26,7 @@ This document describes **repository-wide** setup and
workflow. For **subproject
- [Quick Start](#quick-start)
- [Development Workflow](#development-workflow)
- [Testing](#testing)
+- [API Documentation](#api-documentation)
- [Project-Specific Guides](#project-specific-guides)
- [Troubleshooting](#troubleshooting)
- [References](#references)
@@ -133,6 +134,19 @@ See [testing/README.md](testing/README.md) for more
options and details.
---
+## API Documentation
+
+API reference documentation is generated from source code. To update the
Python API reference content, edit the relevant Python docstrings. Use
`docs/api/` only for generation settings, page metadata, or other API
documentation structure changes. The generated pages are written under
`website/docs/api/` for the Docusaurus site.
+
+**Preview documentation locally:**
+
+```bash
+cd website
+npm run start
+```
+
+---
+
## Project-Specific Guides
Apache Mahout includes several subprojects. Use the root workflow above for
issues, branches, and pull requests; use the guides below for **build, run, and
test** in each area.
diff --git a/docs/api/qumat_qdp.yml b/docs/api/qumat_qdp.yml
index e730b5fe9..2412a528e 100644
--- a/docs/api/qumat_qdp.yml
+++ b/docs/api/qumat_qdp.yml
@@ -25,22 +25,14 @@ loaders:
- qumat_qdp.loader
- qumat_qdp.triton_amd
-# TODO: Trim this filter once the Python package exposes a cleaner public
-# surface for documentation generation.
+# Generated QDP docs intentionally load implementation modules so
pydoc-markdown
+# can render full class and method details. Source docstrings define the public
+# reference surface: documented public objects are rendered, undocumented
fields
+# and internal helpers are omitted.
processors:
- type: filter
- documented_only: false
+ documented_only: true
skip_empty_modules: true
- expression: >-
- (not name.startswith('_') or name == '__init__')
- and name not in (
- 'annotations', 'Mapping', 'import_module', 'ModuleType', 'Any',
- 'dataclass', 'time', 'math', 'os', 'sys', 'warnings', 'Iterator',
- 'TYPE_CHECKING', 'CudaBackendEngine', 'AmdBackendEngine', 'lru_cache',
- 'enum', 'field', 'torch_mod', 'triton_mod', 'triton_lang', 'get_qdp',
- 'get_torch', 'get_backend', 'require_backend'
- )
- and default()
- type: smart
renderer:
@@ -50,11 +42,9 @@ renderer:
add_module_prefix: false
add_method_class_prefix: false
render_toc: false
+ render_module_header: false
header_level_by_type:
- Module: 2
Class: 3
Function: 3
Variable: 3
Method: 4
- render_module_header_template: |
- ## {module_name}
diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts
index e821a4b2a..07c8c58f6 100644
--- a/website/docusaurus.config.ts
+++ b/website/docusaurus.config.ts
@@ -41,7 +41,7 @@ const config: Config = {
'classic',
{
docs: {
- path: '../docs/',
+ path: './docs/',
sidebarPath: './sidebars.ts',
editUrl: 'https://github.com/apache/mahout/tree/main/docs/',
remarkPlugins: [remarkMath],
diff --git a/website/scripts/sync-docs.js b/website/scripts/sync-docs.js
index b0fe4bdb4..d188638fb 100644
--- a/website/scripts/sync-docs.js
+++ b/website/scripts/sync-docs.js
@@ -16,12 +16,16 @@
const fs = require('fs');
const path = require('path');
+const { execFileSync } = require('child_process');
// Configuration
+const REPO_ROOT = path.resolve(__dirname, '../..');
const SOURCE_DIR = path.resolve(__dirname, '../../docs');
const DEST_DIR = path.resolve(__dirname, '../docs');
const BLOG_SOURCE_DIR = path.resolve(__dirname, '../../docs/blog');
const BLOG_DEST_DIR = path.resolve(__dirname, '../blog');
+const API_SOURCE_DIR = path.resolve(__dirname, '../../docs/api');
+const API_DEST_DIR = path.resolve(__dirname, '../docs/api');
// Files that should be preserved during sync (not deleted)
const PRESERVE_FILES = ['.gitignore'];
@@ -33,6 +37,7 @@ const EXCLUDE_PATTERNS = [
/\.pyc$/,
/^__pycache__$/,
/^blog$/, // Blog is synced separately to website/blog
+ /^api$/, // API generator config is rendered separately into website/docs/api
];
/**
@@ -197,6 +202,54 @@ function copyFile(srcPath, destPath) {
fs.copyFileSync(srcPath, destPath);
}
+/**
+ * Run a repository-level command and inherit stdio by default.
+ */
+function runCommand(command, args, options = {}) {
+ return execFileSync(command, args, {
+ cwd: REPO_ROOT,
+ stdio: options.capture ? 'pipe' : 'inherit',
+ encoding: options.capture ? 'utf-8' : undefined,
+ });
+}
+
+/**
+ * Generate Python API reference docs with pydoc-markdown.
+ */
+function generateApiDocs() {
+ fs.rmSync(API_DEST_DIR, { recursive: true, force: true });
+ ensureDir(API_DEST_DIR);
+
+ copyFile(path.join(API_SOURCE_DIR, 'index.md'), path.join(API_DEST_DIR,
'index.md'));
+
+ const pages = [
+ {
+ header: 'qumat_header.md',
+ config: 'qumat.yml',
+ output: 'qumat.md',
+ },
+ {
+ header: 'qumat_qdp_header.md',
+ config: 'qumat_qdp.yml',
+ output: 'qumat_qdp.md',
+ },
+ ];
+
+ runCommand('uv', ['sync', '--frozen', '--group', 'dev']);
+
+ for (const page of pages) {
+ const outputPath = path.join(API_DEST_DIR, page.output);
+ copyFile(path.join(API_SOURCE_DIR, page.header), outputPath);
+
+ const generated = runCommand(
+ 'uv',
+ ['run', '--frozen', '--group', 'dev', 'pydoc-markdown',
path.join('docs/api', page.config)],
+ { capture: true },
+ );
+ fs.appendFileSync(outputPath, generated);
+ }
+}
+
/**
* Recursively sync a directory
*/
@@ -260,6 +313,9 @@ function main() {
console.log('\nSyncing blog posts from /docs/blog...');
const blogStats = syncDirectory(BLOG_SOURCE_DIR, BLOG_DEST_DIR);
+ console.log('\nGenerating Python API reference...');
+ generateApiDocs();
+
console.log(`\nSync complete!`);
console.log(` Docs: ${docsStats.files} files, ${docsStats.dirs}
directories`);
console.log(` Blog: ${blogStats.files} files, ${blogStats.dirs}
directories`);
diff --git a/website/sidebars.ts b/website/sidebars.ts
index 04ab3f439..98a9b0351 100644
--- a/website/sidebars.ts
+++ b/website/sidebars.ts
@@ -56,6 +56,16 @@ const sidebars: SidebarsConfig = {
'advanced/gap-analysis',
],
},
+ {
+ type: 'category',
+ label: 'API Reference (experiments)',
+ collapsed: true,
+ link: {type: 'doc', id: 'api/index'},
+ items: [
+ 'api/qumat',
+ 'api/qumat_qdp',
+ ],
+ },
{
type: 'category',
label: 'Quantum Computing Primer',