From 17dd5c1ef79e21563f51a2491d4d13fede5ebaf1 Mon Sep 17 00:00:00 2001 From: Talley Lambert Date: Sat, 8 Feb 2025 09:45:50 -0500 Subject: [PATCH] docs: use mkdocs-api-autonav to generate nav (#133) * docs: use autonav * remove literate nav * shorten title --- docs/cookbook/embedding.md | 25 ++++++++++++++++++------- docs/hooks.py | 7 +++++-- docs/reference/SUMMARY.md | 0 mkdocs.yml | 19 +++++++++---------- pyproject.toml | 17 ++++++++--------- scripts/gen_ref_nav.py | 37 ------------------------------------- 6 files changed, 40 insertions(+), 65 deletions(-) delete mode 100644 docs/reference/SUMMARY.md delete mode 100644 scripts/gen_ref_nav.py diff --git a/docs/cookbook/embedding.md b/docs/cookbook/embedding.md index edd83d19..62da9f89 100644 --- a/docs/cookbook/embedding.md +++ b/docs/cookbook/embedding.md @@ -1,11 +1,17 @@ -# Embed `ArrayViewer` in a `QWidget` +# Embedding `ArrayViewer` -`ndv` can be embedded in an existing Qt application and enriched with additional elements in a custom layout. -The following document shows some examples of such implementation. +`ndv` can be embedded in an existing Qt (or wx) application and enriched with additional +elements in a custom layout. The following document shows some examples of such +implementation. + +The key in each case is the use of the +[`ArrayViewer.widget`][ndv.controllers.ArrayViewer.widget] method, which returns +a native widget for the current GUI backend. ## Change the content of `ArrayViewer` via push buttons -The following script shows an example on how to dynamically select a data set and load it in the `ArrayViewer`. +The following script shows an example on how to dynamically select a data set +and load it in the `ArrayViewer`. ````python title="examples/cookbook/ndv_embedded.py" --8<-- "examples/cookbook/ndv_embedded.py" @@ -15,7 +21,9 @@ The following script shows an example on how to dynamically select a data set an ## Use multiple `ndv.ArrayViewer` controllers in the same widget -The following script shows an example on how to create multiple instances of the `ArrayViewer` controller in the same widget and load two different datasets in each one. +The following script shows an example on how to create multiple instances of the +`ArrayViewer` controller in the same widget and load two different datasets in +each one. ````python title="examples/cookbook/multi_ndv.py" --8<-- "examples/cookbook/multi_ndv.py" @@ -25,8 +33,11 @@ The following script shows an example on how to create multiple instances of the ## A minimal microscope dashboard using `openwfs` -You can use `ndv` to take an external image source (i.e. a widefield camera) and show its content in real-time in a custom widget embedding `ArrayViewer`. -The script below uses [`openwfs`](https://github.com/IvoVellekoop/openwfs) to generate synthetic images of a sample and continuously update the view, and allows to move the field of view over the X and Y axis. +You can use `ndv` to take an external image source (i.e. a widefield camera) and +show its content in real-time in a custom widget embedding `ArrayViewer`. The +script below uses [`openwfs`](https://github.com/IvoVellekoop/openwfs) to +generate synthetic images of a sample and continuously update the view, and +allows to move the field of view over the X and Y axis. ````python title="examples/cookbook/microscope_dashboard.py" --8<-- "examples/cookbook/microscope_dashboard.py" diff --git a/docs/hooks.py b/docs/hooks.py index 51d9a2a5..a33875cf 100644 --- a/docs/hooks.py +++ b/docs/hooks.py @@ -13,6 +13,7 @@ from __future__ import annotations +import os import re import runpy import subprocess @@ -47,6 +48,7 @@ SCREENSHOT_RE = re.compile(r"{{\s*screenshot:\s*(.+?)\s*}}") # a mapping of {hash -> File} for all screenshots we've generated SCREENSHOTS: defaultdict[int, set[File]] = defaultdict(set) +GEN_SCREENSHOTS = os.getenv("GEN_SCREENSHOTS", "1") not in ("0", "false", "False") def on_startup(command: Literal["build", "gh-deploy", "serve"], dirty: bool) -> None: @@ -117,11 +119,12 @@ def get_screenshot_link(match: re.Match) -> str: # Find all {{ screenshot: some/file.py }}, # generate a screenshot for each file and replace the tag with the image link # this generates two links: one for light mode and one for dark mode - new_markdown = SCREENSHOT_RE.sub(get_screenshot_link, markdown) + if GEN_SCREENSHOTS: + markdown = SCREENSHOT_RE.sub(get_screenshot_link, markdown) # --------------------------------------------------------------------------- - return new_markdown + return markdown # ---------------------------- ScreenShot Generation ---------------------------- diff --git a/docs/reference/SUMMARY.md b/docs/reference/SUMMARY.md deleted file mode 100644 index e69de29b..00000000 diff --git a/mkdocs.yml b/mkdocs.yml index 8e6fb1fa..c434dbd4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -19,9 +19,10 @@ nav: - install.md - motivation.md - env_var.md - - Cookbook: cookbook/ - # This is populated by scripts/gen_ref_nav.py - - API reference: reference/ + - Cookbook: + - cookbook/embedding.md + # This is populated by api-autonav plugin + # - API reference: reference/ theme: name: material @@ -94,26 +95,24 @@ markdown_extensions: permalink: "#" plugins: - - autorefs + - autorefs: + resolve_closest: true - search - minify: minify_html: true minify_js: true minify_css: true cache_safe: true - - gen-files: - scripts: - - scripts/gen_ref_nav.py - - literate-nav: - nav_file: SUMMARY.md - spellcheck: backends: - codespell: dictionaries: [clear] + - api-autonav: + modules: [src/ndv] - mkdocstrings: handlers: python: - import: + inventories: - https://docs.python.org/3/objects.inv - https://numpy.org/doc/stable/objects.inv - https://docs.pydantic.dev/latest/objects.inv diff --git a/pyproject.toml b/pyproject.toml index 764f5bdb..898e3103 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,7 +54,7 @@ pyside = [ "superqt[iconify,pyside6] >=0.7.1", # https://github.com/pyapp-kit/ndv/issues/59 "pyside6 ==6.6.3; sys_platform == 'win32'", - "numpy <2; sys_platform == 'win32'", # needed for pyside6.6 + "numpy <2; sys_platform == 'win32'", # needed for pyside6.6 "pyside6 >=6.4", "qtpy >=2", ] @@ -71,14 +71,13 @@ wx = ["ndv[vispy,wxpython]", "imageio[tifffile]"] test = ["imageio[tifffile]", "pytest-cov", "pytest"] docs = [ - "mkdocs-gen-files==0.5.0", - "mkdocs-literate-nav==0.6.1", - "mkdocs-material==9.5.49", - "mkdocs-minify-plugin==0.8.0", - "mkdocs==1.6.1", - "mkdocstrings-python==1.13.0", - "mkdocs-spellcheck[codespell]==1.1.0", - "mike==2.1.3", + "mkdocs-material >=9.5.49", + "mkdocs-minify-plugin >=0.8.0", + "mkdocs >=1.6.1", + "mkdocstrings-python >=1.14", + "mkdocs-api-autonav", + "mkdocs-spellcheck[codespell] >=1.1.0", + "mike >=2.1.3", "ruff", # EXAMPLES "ndv[vispy,pyqt]", diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py deleted file mode 100644 index 5b1b1d9b..00000000 --- a/scripts/gen_ref_nav.py +++ /dev/null @@ -1,37 +0,0 @@ -"""Generate the code reference pages and navigation.""" - -from pathlib import Path - -import mkdocs_gen_files - -nav = mkdocs_gen_files.Nav() -mod_symbol = '' - -ROOT = Path(__file__).parent.parent -SRC = ROOT / "src" - -for path in sorted(SRC.rglob("*.py")): - module_path = path.relative_to(SRC).with_suffix("") - doc_path = path.relative_to(SRC).with_suffix(".md") - full_doc_path = Path("reference", doc_path) - - parts = tuple(module_path.parts) - - if parts[-1] == "__init__": - parts = parts[:-1] - doc_path = doc_path.with_name("index.md") - full_doc_path = full_doc_path.with_name("index.md") - if any(part.startswith("_") for part in parts): - continue - - nav_parts = [f"{mod_symbol} {part}" for part in parts] - nav[tuple(nav_parts)] = doc_path.as_posix() - - with mkdocs_gen_files.open(full_doc_path, "w") as fd: - ident = ".".join(parts) - fd.write(f"---\ntitle: {ident}\n---\n\n::: {ident}") - - mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path.relative_to(ROOT)) - -with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: - nav_file.writelines(nav.build_literate_nav())