From b482f59f73a813f6f1822233112b74214e1c3554 Mon Sep 17 00:00:00 2001 From: Nate O'Farrell Date: Tue, 3 Mar 2026 15:13:36 -0500 Subject: [PATCH 1/5] Test Wiki Page --- .github/workflows/publish_wiki.yml | 75 ++++++++++++++++++++++++++++++ scripts/generate_docs.py | 8 +++- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish_wiki.yml diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml new file mode 100644 index 0000000..33eeb91 --- /dev/null +++ b/.github/workflows/publish_wiki.yml @@ -0,0 +1,75 @@ +name: publish wiki docs + +on: + push: + branches: + - "main" + paths: + - "src/nxlib/**" + - "scripts/generate_docs.py" + workflow_dispatch: + pull_request: + +permissions: + contents: write + +jobs: + publish-wiki: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Install uv + uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6 + + - name: Install nxlib and dev dependencies + run: uv sync --dev + + - name: Generate markdown docs + run: uv run python scripts/generate_docs.py docs_build --format markdown + + - name: Publish to wiki + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + + wiki_url="https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.wiki.git" + git clone "${wiki_url}" wiki_repo + + # Remove previously generated docs so deleted modules don't linger + find wiki_repo -name '*.md' ! -name '_Sidebar.md' ! -name '_Footer.md' -delete + + # Copy freshly generated markdown into the wiki repo + cp -r docs_build/* wiki_repo/ + + # Use the top-level nxlib page as the wiki Home page + if [ -f wiki_repo/nxlib.md ]; then + cp wiki_repo/nxlib.md wiki_repo/Home.md + fi + + # Build a sidebar with links to every page + { + echo "### nxlib docs" + echo "" + echo "- [Home](Home)" + find wiki_repo -name '*.md' -not -name 'Home.md' \ + -not -name '_Sidebar.md' -not -name '_Footer.md' \ + | sort | while read -r f; do + rel="${f#wiki_repo/}" + page="${rel%.md}" + name="${page##*/}" + echo "- [${name}](${page})" + done + } > wiki_repo/_Sidebar.md + + cd wiki_repo + git add --all + if git diff --cached --quiet; then + echo "No documentation changes to publish." + else + git commit -m "Update wiki docs from ${GITHUB_SHA::8}" + git push + fi diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 452bce3..5053e5e 100644 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -67,6 +67,12 @@ def _mock_import(name, globals=[], locals={}, fromlist=[], level=0): parser.add_argument( "build_dir", type=Path, help="Output directory for documentation build." ) + parser.add_argument( + "--format", + choices=["html", "markdown"], + default="html", + help="Output format (default: html).", + ) args = parser.parse_args() # Replace the import function with the mock function above. This allows # a workaround when pdoc tries to import NXOpen. @@ -82,4 +88,4 @@ def _mock_import(name, globals=[], locals={}, fromlist=[], level=0): pdoc.render.configure(docformat="numpy") # pyright: ignore[reportPrivateImportUsage] # Build the documentation - doc = pdoc.pdoc("nxlib", output_directory=args.build_dir) + doc = pdoc.pdoc("nxlib", output_directory=args.build_dir, format=args.format) From 73172b08e7e8b9beb524f84578761ec6de040c46 Mon Sep 17 00:00:00 2001 From: Nate O'Farrell Date: Tue, 3 Mar 2026 15:17:57 -0500 Subject: [PATCH 2/5] md to html --- .github/workflows/publish_wiki.yml | 22 +++++++++++++++++++--- scripts/generate_docs.py | 8 +------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml index 33eeb91..d21874d 100644 --- a/.github/workflows/publish_wiki.yml +++ b/.github/workflows/publish_wiki.yml @@ -26,8 +26,24 @@ jobs: - name: Install nxlib and dev dependencies run: uv sync --dev - - name: Generate markdown docs - run: uv run python scripts/generate_docs.py docs_build --format markdown + - name: Install pandoc + run: sudo apt-get update && sudo apt-get install -y pandoc + + - name: Generate HTML docs + run: uv run python scripts/generate_docs.py docs_build + + - name: Convert HTML to Markdown + run: | + # pdoc 15 only outputs HTML; convert to Markdown for the wiki (see pdoc3/pdoc#257) + mkdir -p docs_md + find docs_build -name '*.html' -not -name 'index.html' | while read -r f; do + rel="${f#docs_build/}" + out="docs_md/${rel%.html}.md" + mkdir -p "$(dirname "$out")" + pandoc "$f" --from html --to gfm -o "$out" + done + # Fix internal links: .html -> .md (GitHub Wiki expects no extension or .md) + find docs_md -name '*.md' -exec sed -i 's/\.html"/"/g; s/\.html#/#/g' {} \; - name: Publish to wiki env: @@ -43,7 +59,7 @@ jobs: find wiki_repo -name '*.md' ! -name '_Sidebar.md' ! -name '_Footer.md' -delete # Copy freshly generated markdown into the wiki repo - cp -r docs_build/* wiki_repo/ + cp -r docs_md/* wiki_repo/ # Use the top-level nxlib page as the wiki Home page if [ -f wiki_repo/nxlib.md ]; then diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py index 5053e5e..81bdff1 100644 --- a/scripts/generate_docs.py +++ b/scripts/generate_docs.py @@ -67,12 +67,6 @@ def _mock_import(name, globals=[], locals={}, fromlist=[], level=0): parser.add_argument( "build_dir", type=Path, help="Output directory for documentation build." ) - parser.add_argument( - "--format", - choices=["html", "markdown"], - default="html", - help="Output format (default: html).", - ) args = parser.parse_args() # Replace the import function with the mock function above. This allows # a workaround when pdoc tries to import NXOpen. @@ -88,4 +82,4 @@ def _mock_import(name, globals=[], locals={}, fromlist=[], level=0): pdoc.render.configure(docformat="numpy") # pyright: ignore[reportPrivateImportUsage] # Build the documentation - doc = pdoc.pdoc("nxlib", output_directory=args.build_dir, format=args.format) + pdoc.pdoc("nxlib", output_directory=args.build_dir) From 6a487003681caacfea5fff5585c3b3b6115b1714 Mon Sep 17 00:00:00 2001 From: Nate O'Farrell Date: Tue, 3 Mar 2026 15:24:08 -0500 Subject: [PATCH 3/5] clean --- .github/workflows/publish_wiki.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml index d21874d..5189bc3 100644 --- a/.github/workflows/publish_wiki.yml +++ b/.github/workflows/publish_wiki.yml @@ -44,6 +44,8 @@ jobs: done # Fix internal links: .html -> .md (GitHub Wiki expects no extension or .md) find docs_md -name '*.md' -exec sed -i 's/\.html"/"/g; s/\.html#/#/g' {} \; + # Strip pdoc/Pygments line numbers from code blocks (e.g. " 1 def foo()" -> " def foo()"; use single \s to keep indent) + find docs_md -name '*.md' -exec perl -i -pe 'if (/^```/) { $in = !$in } elsif ($in) { s/^\s*\d+\s// }' {} \; - name: Publish to wiki env: @@ -58,15 +60,23 @@ jobs: # Remove previously generated docs so deleted modules don't linger find wiki_repo -name '*.md' ! -name '_Sidebar.md' ! -name '_Footer.md' -delete - # Copy freshly generated markdown into the wiki repo - cp -r docs_md/* wiki_repo/ + # GitHub Wiki does not support path-based links (e.g. nxlib/nxopen/uf). + # Copy with flattened names so pages are nxlib, nxlib-geometry, nxlib-nxopen-uf, etc. + find docs_md -name '*.md' | while read -r f; do + rel="${f#docs_md/}" + flat="${rel//\//-}" + cp "$f" "wiki_repo/$flat" + done + + # Rewrite internal links: ](path/with/slashes) -> ](path-with-slashes) + find wiki_repo -name '*.md' -exec perl -i -pe 's/\](([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' {} \; # Use the top-level nxlib page as the wiki Home page if [ -f wiki_repo/nxlib.md ]; then cp wiki_repo/nxlib.md wiki_repo/Home.md fi - # Build a sidebar with links to every page + # Build a sidebar with links to every page (flat names) { echo "### nxlib docs" echo "" @@ -76,8 +86,7 @@ jobs: | sort | while read -r f; do rel="${f#wiki_repo/}" page="${rel%.md}" - name="${page##*/}" - echo "- [${name}](${page})" + echo "- [${page}](${page})" done } > wiki_repo/_Sidebar.md From d8ed7cfda45ccb078549e6aa9d80eaeaaa15d0b7 Mon Sep 17 00:00:00 2001 From: Nate O'Farrell Date: Tue, 3 Mar 2026 15:33:01 -0500 Subject: [PATCH 4/5] direct md --- .github/workflows/publish_wiki.yml | 70 +++++++---------------------- .gitignore | 3 ++ pyproject.toml | 1 + scripts/generate_md_docs.py | 72 ++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 scripts/generate_md_docs.py diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml index 5189bc3..68acc2e 100644 --- a/.github/workflows/publish_wiki.yml +++ b/.github/workflows/publish_wiki.yml @@ -6,7 +6,7 @@ on: - "main" paths: - "src/nxlib/**" - - "scripts/generate_docs.py" + - "scripts/generate_md_docs.py" workflow_dispatch: pull_request: @@ -26,26 +26,8 @@ jobs: - name: Install nxlib and dev dependencies run: uv sync --dev - - name: Install pandoc - run: sudo apt-get update && sudo apt-get install -y pandoc - - - name: Generate HTML docs - run: uv run python scripts/generate_docs.py docs_build - - - name: Convert HTML to Markdown - run: | - # pdoc 15 only outputs HTML; convert to Markdown for the wiki (see pdoc3/pdoc#257) - mkdir -p docs_md - find docs_build -name '*.html' -not -name 'index.html' | while read -r f; do - rel="${f#docs_build/}" - out="docs_md/${rel%.html}.md" - mkdir -p "$(dirname "$out")" - pandoc "$f" --from html --to gfm -o "$out" - done - # Fix internal links: .html -> .md (GitHub Wiki expects no extension or .md) - find docs_md -name '*.md' -exec sed -i 's/\.html"/"/g; s/\.html#/#/g' {} \; - # Strip pdoc/Pygments line numbers from code blocks (e.g. " 1 def foo()" -> " def foo()"; use single \s to keep indent) - find docs_md -name '*.md' -exec perl -i -pe 'if (/^```/) { $in = !$in } elsif ($in) { s/^\s*\d+\s// }' {} \; + - name: Generate Markdown docs + run: uv run python scripts/generate_md_docs.py docs_md - name: Publish to wiki env: @@ -53,48 +35,28 @@ jobs: run: | git config --global user.name "github-actions[bot]" git config --global user.email "github-actions[bot]@users.noreply.github.com" + git clone "https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.wiki.git" wiki_repo - wiki_url="https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}.wiki.git" - git clone "${wiki_url}" wiki_repo + find wiki_repo -mindepth 1 ! -path 'wiki_repo/.git' ! -path 'wiki_repo/.git/*' -delete - # Remove previously generated docs so deleted modules don't linger - find wiki_repo -name '*.md' ! -name '_Sidebar.md' ! -name '_Footer.md' -delete - - # GitHub Wiki does not support path-based links (e.g. nxlib/nxopen/uf). - # Copy with flattened names so pages are nxlib, nxlib-geometry, nxlib-nxopen-uf, etc. - find docs_md -name '*.md' | while read -r f; do - rel="${f#docs_md/}" - flat="${rel//\//-}" + # Copy with flat names (wiki doesn't support path links), rewrite ](a/b/c) -> ](a-b-c) + : > wiki_repo/.pages + find docs_md -name '*.md' | sort | while read -r f; do + flat="${f#docs_md/}"; flat="${flat//\//-}" cp "$f" "wiki_repo/$flat" + perl -i -pe 's/\](([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' "wiki_repo/$flat" + echo "${flat%.md}" >> wiki_repo/.pages done - # Rewrite internal links: ](path/with/slashes) -> ](path-with-slashes) - find wiki_repo -name '*.md' -exec perl -i -pe 's/\](([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' {} \; - - # Use the top-level nxlib page as the wiki Home page - if [ -f wiki_repo/nxlib.md ]; then - cp wiki_repo/nxlib.md wiki_repo/Home.md - fi - - # Build a sidebar with links to every page (flat names) + [ -f wiki_repo/nxlib.md ] && cp wiki_repo/nxlib.md wiki_repo/Home.md { echo "### nxlib docs" echo "" echo "- [Home](Home)" - find wiki_repo -name '*.md' -not -name 'Home.md' \ - -not -name '_Sidebar.md' -not -name '_Footer.md' \ - | sort | while read -r f; do - rel="${f#wiki_repo/}" - page="${rel%.md}" - echo "- [${page}](${page})" - done + sed 's/^\(.*\)$/- [\1](\1)/' wiki_repo/.pages } > wiki_repo/_Sidebar.md + rm -f wiki_repo/.pages cd wiki_repo - git add --all - if git diff --cached --quiet; then - echo "No documentation changes to publish." - else - git commit -m "Update wiki docs from ${GITHUB_SHA::8}" - git push - fi + git add -A + git diff --cached --quiet || { git commit -m "Update wiki docs from ${GITHUB_SHA::8}"; git push; } diff --git a/.gitignore b/.gitignore index 0fbe32d..3950dc7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,9 @@ # mech_data_tools specific typings/ +# generated markdown docs (scripts/generate_md_docs.py) +docs_md/ + # python *.pyc __pycache__ diff --git a/pyproject.toml b/pyproject.toml index 0c18ff2..fdeebd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,6 +59,7 @@ where = ["src"] [dependency-groups] dev = [ "pdoc==15.0.4", + "pydoc-markdown>=4.0", "pyright==1.1.403", "pytest==8.4.1", "ruff==0.13.3", diff --git a/scripts/generate_md_docs.py b/scripts/generate_md_docs.py new file mode 100644 index 0000000..dad49bf --- /dev/null +++ b/scripts/generate_md_docs.py @@ -0,0 +1,72 @@ +# Copyright 2026 Commonwealth Fusion Systems (CFS), all rights reserved. +# This entire source code file represents the sole intellectual property of CFS. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Generate nxlib API documentation as Markdown using pydoc-markdown. + +Output is written as one .md file per module under the given build directory, +mirroring the package layout (e.g. nxlib/nxopen/uf.md). No import of nxlib +is required (pydoc-markdown parses source via docspec), so NXOpen need not be +installed. +""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from pydoc_markdown import PydocMarkdown +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer + + +def main() -> None: + parser = argparse.ArgumentParser( + "generate_md_docs", + description="Generate nxlib API documentation as Markdown (wiki-friendly).", + ) + parser.add_argument( + "build_dir", + type=Path, + help="Output directory for Markdown files (e.g. docs_md).", + ) + args = parser.parse_args() + + build_dir = args.build_dir.resolve() + build_dir.mkdir(parents=True, exist_ok=True) + + session = PydocMarkdown() + loader = session.loaders[0] + assert isinstance(loader, PythonLoader) + loader.search_path = ["src"] + loader.packages = ["nxlib"] + + modules = session.load_modules() + session.process(modules) + + renderer = session.renderer + assert isinstance(renderer, MarkdownRenderer) + renderer.render_toc = True + renderer.insert_header_anchors = True + + for module in modules: + out_path = build_dir / f"{module.name.replace('.', '/')}.md" + out_path.parent.mkdir(parents=True, exist_ok=True) + md = renderer.render_to_string([module]) + out_path.write_text(md, encoding="utf-8") + + print(f"Wrote {len(modules)} Markdown files under {build_dir}") + + +if __name__ == "__main__": + main() From bbc43d20aaece32e958c1ccf0c98618b37385f5f Mon Sep 17 00:00:00 2001 From: Nate O'Farrell Date: Tue, 3 Mar 2026 15:35:23 -0500 Subject: [PATCH 5/5] regex --- .github/workflows/publish_wiki.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_wiki.yml b/.github/workflows/publish_wiki.yml index 68acc2e..724a3bd 100644 --- a/.github/workflows/publish_wiki.yml +++ b/.github/workflows/publish_wiki.yml @@ -44,7 +44,7 @@ jobs: find docs_md -name '*.md' | sort | while read -r f; do flat="${f#docs_md/}"; flat="${flat//\//-}" cp "$f" "wiki_repo/$flat" - perl -i -pe 's/\](([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' "wiki_repo/$flat" + perl -i -pe 's/\]\(([^)]+)\)/"](" . ($1 =~ s|\/|-|gr) . ")"/ge' "wiki_repo/$flat" echo "${flat%.md}" >> wiki_repo/.pages done