From 9a45d76693efdd57725c36cd5cd97f0195c341bf Mon Sep 17 00:00:00 2001 From: Ivan Ogasawara Date: Wed, 29 Apr 2026 02:37:20 +0000 Subject: [PATCH] docs: Move from mkdocs to quarto --- .github/workflows/docs.yaml | 2 +- .github/workflows/release.yaml | 2 +- .gitignore | 5 + .makim.yaml | 6 +- AGENTS.md | 6 +- docs/.gitignore | 2 + docs/_quarto.yml | 130 ++++ mkdocs.yaml | 197 ------ packages/arx/tests/python/test_settings.py | 4 +- packages/irx/pyproject.toml | 10 +- poetry.lock | 686 +++++---------------- pyproject.toml | 10 +- scripts/gen_api_docs.py | 484 +++++++++++++++ scripts/gen_ref_nav.py | 52 -- 14 files changed, 776 insertions(+), 820 deletions(-) create mode 100644 docs/.gitignore create mode 100644 docs/_quarto.yml delete mode 100644 mkdocs.yaml create mode 100644 scripts/gen_api_docs.py delete mode 100644 scripts/gen_ref_nav.py diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 924d3bf..a3cbf6f 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -38,7 +38,7 @@ jobs: poetry config virtualenvs.create false poetry install - - name: Generate documentation with changes from semantic-release + - name: Generate documentation run: makim --verbose docs.build - name: GitHub Pages action diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9464285..74c2bc7 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -51,7 +51,7 @@ jobs: poetry config pypi-token.pypi ${PYPI_TOKEN} makim release.ci - - name: Generate documentation with changes from semantic-release + - name: Generate documentation if: ${{ github.event_name == 'workflow_dispatch' }} run: makim docs.build diff --git a/.gitignore b/.gitignore index 735fb3d..4fac5f9 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,11 @@ ENV/ # arx *.x.o +/docs/api/ +/docs/_site/ +.quarto-tmp/ +.quarto-cache/ +.deno-cache/ # llm .codex diff --git a/.makim.yaml b/.makim.yaml index ade60bd..ec70b4e 100644 --- a/.makim.yaml +++ b/.makim.yaml @@ -362,12 +362,12 @@ groups: build: help: build documentation run: | - mkdocs build --config-file mkdocs.yaml - echo "arxlang.org" > ./build/CNAME + bash -lc 'mkdir -p .quarto-tmp .quarto-cache .deno-cache && rm -rf build && TMPDIR="$PWD/.quarto-tmp" XDG_CACHE_HOME="$PWD/.quarto-cache" DENO_DIR="$PWD/.deno-cache" quarto render docs && cp -a docs/_site build && echo "arxlang.org" > ./build/CNAME' preview: help: preview documentation page locally - run: mkdocs serve --watch docs --config-file mkdocs.yaml + run: | + bash -lc 'mkdir -p .quarto-tmp .quarto-cache .deno-cache && TMPDIR="$PWD/.quarto-tmp" XDG_CACHE_HOME="$PWD/.quarto-cache" DENO_DIR="$PWD/.deno-cache" quarto preview docs' release: vars: diff --git a/AGENTS.md b/AGENTS.md index 48c87c6..ae76e40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,7 +33,7 @@ Use this guidance for any change inside the Arx compiler repository: - `irx` for semantic analysis, lowering, and code generation - `astx` as the upstream node library consumed through IRx - `jsonschema` + `pyyaml` for Douki docstring validation -- Docs stack: MkDocs + Material + mkdocstrings +- Docs stack: Quarto ## Repository Layout @@ -265,7 +265,7 @@ makim all.lint makim all.ci # docs -mkdocs build --config-file mkdocs.yaml +makim docs.build ``` Codegen-focused checks: @@ -304,7 +304,7 @@ When behavior changes, update docs in same PR: - language overview and getting-started examples - `docs/library/*` for syntax/placement rules -- API docs are generated via mkdocstrings (`scripts/gen_ref_nav.py`) +- API docs are generated for Quarto via `scripts/gen_api_docs.py` If embedding Arx docstrings inside Markdown code examples, prefer quadruple fences around the code block to safely include inner triple backticks. diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..ad29309 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +/.quarto/ +**/*.quarto_ipynb diff --git a/docs/_quarto.yml b/docs/_quarto.yml new file mode 100644 index 0000000..60eed4f --- /dev/null +++ b/docs/_quarto.yml @@ -0,0 +1,130 @@ +project: + type: website + output-dir: _site + pre-render: + - python ../scripts/gen_api_docs.py + +website: + title: ArxLang + site-url: https://arxlang.org + repo-url: https://github.com/arxlang/arx + favicon: favicon.ico + page-footer: "Copyright © 2022, ArxLang Team" + navbar: + logo: images/arx.png + right: + - icon: github + href: https://github.com/arxlang/arx + - text: Community + href: discord.md + sidebar: + style: docked + search: true + contents: + - text: Home + href: index.md + - text: Getting Started + href: getting-started.md + - section: Library + contents: + - text: Overview + href: library/index.md + - text: Modules + href: library/modules.md + - text: Functions + href: library/functions.md + - text: Classes + href: library/classes.md + - text: Data Types + href: library/datatypes.md + - text: Built-in Types + href: library/built-in-types.md + - text: Control Flow + href: library/control-flow.md + - text: Docstrings + href: library/docstrings.md + - section: ASTx + contents: + - text: Overview + href: astx/index.md + - text: Installation + href: astx/installation.md + - text: Conventions + href: astx/conventions.md + - text: Contributing + href: astx/contributing.md + - section: Tutorials + contents: + - text: Getting Started + href: astx/tutorials/get-started.ipynb + - text: Literals + href: astx/tutorials/literals.ipynb + - text: Variables + href: astx/tutorials/variables.ipynb + - text: Functions + href: astx/tutorials/functions.ipynb + - text: For Loops + href: astx/tutorials/for-loop.ipynb + - text: Context + href: astx/tutorials/context.ipynb + - text: Fibonacci + href: astx/tutorials/fibonacci.ipynb + - text: Historical Changelog + href: astx/changelog.md + - section: IRx + contents: + - text: Overview + href: irx/index.md + - text: Installation + href: irx/installation.md + - text: Architecture + href: irx/architecture.md + - text: Semantic Contract + href: irx/semantic-contract.md + - text: Runtime Features + href: irx/runtime-features.md + - text: Buffer View Model + href: irx/buffer-view-model.md + - text: Class Model + href: irx/class-model.md + - text: Contributing + href: irx/contributing.md + - section: Tutorials + contents: + - text: Getting Started + href: irx/tutorials/get-started.ipynb + - text: Historical Changelog + href: irx/changelog.md + - text: API Docs + href: api/index.md + - text: Syntax + href: syntax.md + - text: Roadmap + href: roadmap.md + - text: Contributing Guide + href: contributing.md + - text: Sponsor + href: sponsor.md + - text: Partners + href: partners.md + - text: Code of Conduct + href: coc.md + - text: Community + href: discord.md + - text: Governance + href: governance.md + - text: Changelog + href: changelog.md + +format: + html: + theme: + light: cosmo + dark: darkly + toc: true + code-copy: true + code-overflow: wrap + link-external-newwindow: true + +execute: + enabled: false diff --git a/mkdocs.yaml b/mkdocs.yaml deleted file mode 100644 index 43bdc3c..0000000 --- a/mkdocs.yaml +++ /dev/null @@ -1,197 +0,0 @@ -site_name: ArxLang -site_url: https://arxlang.org -repo_url: https://github.com/arxlang/arx -docs_dir: ./docs -site_dir: ./build - -nav: - - Home: index.md - - Getting Started: getting-started.md - - Library: - - Overview: library/index.md - - Modules: library/modules.md - - Functions: library/functions.md - - Classes: library/classes.md - - Data Types: library/datatypes.md - - Built-in Types: library/built-in-types.md - - Control Flow: library/control-flow.md - - Docstrings: library/docstrings.md - - ASTx: - - Overview: astx/index.md - - Installation: astx/installation.md - - Conventions: astx/conventions.md - - Contributing: astx/contributing.md - - Tutorials: - - Getting Started: astx/tutorials/get-started.ipynb - - Literals: astx/tutorials/literals.ipynb - - Variables: astx/tutorials/variables.ipynb - - Functions: astx/tutorials/functions.ipynb - - For Loops: astx/tutorials/for-loop.ipynb - - Context: astx/tutorials/context.ipynb - - Fibonacci: astx/tutorials/fibonacci.ipynb - - Historical Changelog: astx/changelog.md - - IRx: - - Overview: irx/index.md - - Installation: irx/installation.md - - Architecture: irx/architecture.md - - Semantic Contract: irx/semantic-contract.md - - Runtime Features: irx/runtime-features.md - - Buffer View Model: irx/buffer-view-model.md - - Class Model: irx/class-model.md - - Contributing: irx/contributing.md - - Tutorials: - - Getting Started: irx/tutorials/get-started.ipynb - - Historical Changelog: irx/changelog.md - - API Docs: api/ - - Syntax: syntax.md - - Roadmap: roadmap.md - - Contributing Guide: contributing.md - - Sponsor: sponsor.md - - Partners: partners.md - - Code of Conduct: coc.md - - Community: discord.md - - Governance: governance.md - - Changelog: changelog.md - -theme: - name: material - features: - - content.code.annotate - - content.code.copy - - content.tabs.link - - header.autohide - - navigation.indexes - - navigation.instant - - search.highlight - - search.share - - search.suggest - icon: - repo: fontawesome/brands/github - logo: ./images/arx.png - favicon: ./images/favicon.ico - palette: - # Palette toggle for light mode - - scheme: default - primary: white - accent: lime - toggle: - icon: material/weather-night - name: Switch to dark mode - - # Palette toggle for dark mode - - scheme: slate - primary: white - accent: lime - toggle: - icon: material/weather-sunny - name: Switch to light mode - -plugins: - - search - - macros - - autorefs - # - exclude: - # glob: - # - backends/template.md - - gen-files: - scripts: - - scripts/gen_ref_nav.py - - literate-nav: - nav_file: SUMMARY.md - - mkdocstrings: - enable_inventory: true - handlers: - python: - paths: - - packages/arx/src - - packages/astx/src - - packages/irx/src - - inventories: - - https://docs.python.org/3/objects.inv - options: - docstring_options: - ignore_init_summary: true - docstring_section_style: list - docstring_style: google - filters: ["!^_"] - heading_level: 1 - inherited_members: true - merge_init_into_class: true - separate_signature: true - # show_category_heading: true - # show_modules: true - show_root_full_path: false - show_root_heading: true - # show_root_toc_entry: true - show_signature_annotations: true - show_source: true - show_symbol_type_heading: true - show_symbol_type_toc: true - signature_crossrefs: true - summary: true - - mkdocs-jupyter: - execute: false - ignore: - - "*.py" - - ".ipynb_checkpoints/*" - include_source: true - include_requirejs: true - -markdown_extensions: - - admonition - - attr_list - - codehilite - - def_list - - footnotes - - md_in_html - - meta - - pymdownx.emoji: - emoji_index: !!python/name:material.extensions.emoji.twemoji - emoji_generator: !!python/name:material.extensions.emoji.to_svg - options: - custom_icons: - - docs/static/icons - - pymdownx.details - - pymdownx.highlight: - pygments_lang_class: true - - pymdownx.inlinehilite: - style_plain_text: python - - pymdownx.magiclink: - provider: github - repo_url_shortener: true - - pymdownx.saneheaders - - pymdownx.snippets - - pymdownx.superfences - - pymdownx.tabbed: - alternate_style: true - - tables - - toc: - permalink: true - -extra: - project_name: "Arx" - team: - - name: "Active maintainers" - members: - - xmnlab - - name: "Former maintainers" - members: - - xmnlab - social: - - icon: fontawesome/brands/twitter - link: https://twitter.com/xmnlab - - icon: fontawesome/brands/github - link: https://github.com/arxlang/arx - support_levels: - supported: - icon: :material-check-decagram:{ .verified } - description: Tested in CI. If this doesn't work for you, please [file an issue](https://github.com/arxlang/arx/issues/new). - bug: - icon: :material-bug:{ .bug } - description: Should work but doesn't because upstream is broken. Supported on a best-effort basis. - unsupported: - icon: :material-cancel:{ .cancel } - description: Unlikely to ever be supported or no upstream support. - -copyright: "Copyright © 2022, ArxLang Team" diff --git a/packages/arx/tests/python/test_settings.py b/packages/arx/tests/python/test_settings.py index 8acc857..bbf98e6 100644 --- a/packages/arx/tests/python/test_settings.py +++ b/packages/arx/tests/python/test_settings.py @@ -340,7 +340,7 @@ def test_dependency_groups_support_multiple_named_groups() -> None: [dependency-groups] dev = ["pytest", "ruff", "mypy"] test = ["pytest", "coverage"] - docs = ["mkdocs"] + docs = ["quarto-cli"] """ ).lstrip() @@ -350,7 +350,7 @@ def test_dependency_groups_support_multiple_named_groups() -> None: assert settings.dependency_groups == { "dev": ("pytest", "ruff", "mypy"), "test": ("pytest", "coverage"), - "docs": ("mkdocs",), + "docs": ("quarto-cli",), } diff --git a/packages/irx/pyproject.toml b/packages/irx/pyproject.toml index 0b66b45..44a43b0 100644 --- a/packages/irx/pyproject.toml +++ b/packages/irx/pyproject.toml @@ -52,17 +52,9 @@ vulture = ">=2.9.1" mccabe = ">=0.6.1" ipython = ">=7" ipykernel = ">=6.0.0" -mkdocs = ">=1.3" -mkdocs-exclude = ">=1.0.2" -mkdocs-jupyter = ">=0.24.7" -mkdocs-literate-nav = ">=0.4.1" -mkdocs-macros-plugin = ">=0.6.3" -mkdocs-material = ">=8" -mkdocstrings = {version=">=0.19.0", extras=["python"]} -mkdocstrings-python = "<2" +quarto-cli = ">=1.9.0" makim = "1.25.0" jupyterlab = ">=4.0.7" -mkdocs-gen-files = ">=0.5.0" nbmake = ">=1.5.3" pytest-xdist = "^3.8.0" douki = ">=0.12.1" diff --git a/poetry.lock b/poetry.lock index 576bf6f..9ad1748 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.1 and should not be changed by hand. [[package]] name = "annotated-doc" @@ -282,26 +282,6 @@ files = [ [package.extras] dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] -[[package]] -name = "backrefs" -version = "6.2" -description = "A wrapper around re and regex that adds additional back references." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "backrefs-6.2-py310-none-any.whl", hash = "sha256:0fdc7b012420b6b144410342caeb8adc54c6866cf12064abc9bb211302e496f8"}, - {file = "backrefs-6.2-py311-none-any.whl", hash = "sha256:08aa7fae530c6b2361d7bdcbda1a7c454e330cc9dbcd03f5c23205e430e5c3be"}, - {file = "backrefs-6.2-py312-none-any.whl", hash = "sha256:c3f4b9cb2af8cda0d87ab4f57800b57b95428488477be164dd2b47be54db0c90"}, - {file = "backrefs-6.2-py313-none-any.whl", hash = "sha256:12df81596ab511f783b7d87c043ce26bc5b0288cf3bb03610fe76b8189282b2b"}, - {file = "backrefs-6.2-py314-none-any.whl", hash = "sha256:e5f805ae09819caa1aa0623b4a83790e7028604aa2b8c73ba602c4454e665de7"}, - {file = "backrefs-6.2-py39-none-any.whl", hash = "sha256:664e33cd88c6840b7625b826ecf2555f32d491800900f5a541f772c485f7cda7"}, - {file = "backrefs-6.2.tar.gz", hash = "sha256:f44ff4d48808b243b6c0cdc6231e22195c32f77046018141556c66f8bab72a49"}, -] - -[package.extras] -extras = ["regex"] - [[package]] name = "bandit" version = "1.9.4" @@ -732,6 +712,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -1145,24 +1126,6 @@ files = [ [package.extras] speedup = ["python-levenshtein (>=0.12)"] -[[package]] -name = "ghp-import" -version = "2.1.0" -description = "Copy your docs directly to the gh-pages branch." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, - {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, -] - -[package.dependencies] -python-dateutil = ">=2.8.1" - -[package.extras] -dev = ["flake8", "markdown", "twine", "wheel"] - [[package]] name = "greenlet" version = "3.3.2" @@ -1231,56 +1194,6 @@ files = [ docs = ["Sphinx", "furo"] test = ["objgraph", "psutil", "setuptools"] -[[package]] -name = "griffe" -version = "2.0.0" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "griffe-2.0.0-py3-none-any.whl", hash = "sha256:5418081135a391c3e6e757a7f3f156f1a1a746cc7b4023868ff7d5e2f9a980aa"}, - {file = "griffe-2.0.0.tar.gz", hash = "sha256:c68979cd8395422083a51ea7cf02f9c119d889646d99b7b656ee43725de1b80f"}, -] - -[package.dependencies] -griffecli = "2.0.0" -griffelib = "2.0.0" - -[package.extras] -pypi = ["griffelib[pypi] (==2.0.0)"] - -[[package]] -name = "griffecli" -version = "2.0.0" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "griffecli-2.0.0-py3-none-any.whl", hash = "sha256:9f7cd9ee9b21d55e91689358978d2385ae65c22f307a63fb3269acf3f21e643d"}, - {file = "griffecli-2.0.0.tar.gz", hash = "sha256:312fa5ebb4ce6afc786356e2d0ce85b06c1c20d45abc42d74f0cda65e159f6ef"}, -] - -[package.dependencies] -colorama = ">=0.4" -griffelib = "2.0.0" - -[[package]] -name = "griffelib" -version = "2.0.0" -description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "griffelib-2.0.0-py3-none-any.whl", hash = "sha256:01284878c966508b6d6f1dbff9b6fa607bc062d8261c5c7253cb285b06422a7f"}, - {file = "griffelib-2.0.0.tar.gz", hash = "sha256:e504d637a089f5cab9b5daf18f7645970509bf4f53eda8d79ed71cce8bd97934"}, -] - -[package.extras] -pypi = ["pip (>=24.0)", "platformdirs (>=4.2)", "wheel (>=0.42)"] - [[package]] name = "h11" version = "0.16.0" @@ -1293,18 +1206,6 @@ files = [ {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] -[[package]] -name = "hjson" -version = "3.1.0" -description = "Hjson, a user interface for JSON." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "hjson-3.1.0-py3-none-any.whl", hash = "sha256:65713cdcf13214fb554eb8b4ef803419733f4f5e551047c9b711098ab7186b89"}, - {file = "hjson-3.1.0.tar.gz", hash = "sha256:55af475a27cf83a7969c808399d7bccdec8fb836a07ddbd574587593b9cdcf75"}, -] - [[package]] name = "httpcore" version = "1.0.9" @@ -1529,6 +1430,28 @@ files = [ [package.dependencies] pygments = "*" +[[package]] +name = "ipywidgets" +version = "8.1.8" +description = "Jupyter interactive widgets" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e"}, + {file = "ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668"}, +] + +[package.dependencies] +comm = ">=0.1.3" +ipython = ">=6.1.0" +jupyterlab_widgets = ">=3.0.15,<3.1.0" +traitlets = ">=4.3.1" +widgetsnbextension = ">=4.0.14,<4.1.0" + +[package.extras] +test = ["ipykernel", "jsonschema", "pytest (>=3.6.0)", "pytest-cov", "pytz"] + [[package]] name = "isoduration" version = "20.11.0" @@ -1652,6 +1575,26 @@ files = [ [package.dependencies] referencing = ">=0.31.0" +[[package]] +name = "jupyter" +version = "1.1.1" +description = "Jupyter metapackage. Install all the Jupyter components in one go." +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83"}, + {file = "jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a"}, +] + +[package.dependencies] +ipykernel = "*" +ipywidgets = "*" +jupyter-console = "*" +jupyterlab = "*" +nbconvert = "*" +notebook = "*" + [[package]] name = "jupyter-client" version = "8.8.0" @@ -1676,6 +1619,31 @@ docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphi orjson = ["orjson"] test = ["anyio", "coverage", "ipykernel (>=6.14)", "msgpack", "mypy ; platform_python_implementation != \"PyPy\"", "paramiko ; sys_platform == \"win32\"", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.6.2)", "pytest-timeout"] +[[package]] +name = "jupyter-console" +version = "6.6.3" +description = "Jupyter terminal console" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485"}, + {file = "jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539"}, +] + +[package.dependencies] +ipykernel = ">=6.14" +ipython = "*" +jupyter-client = ">=7.0.0" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +prompt-toolkit = ">=3.0.30" +pygments = "*" +pyzmq = ">=17" +traitlets = ">=5.4" + +[package.extras] +test = ["flaky", "pexpect", "pytest"] + [[package]] name = "jupyter-core" version = "5.9.1" @@ -1869,35 +1837,17 @@ openapi = ["openapi-core (>=0.18.0,<0.19.0)", "ruamel-yaml"] test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-validator (>=0.6.0,<0.8.0)", "pytest (>=7.0,<8)", "pytest-console-scripts", "pytest-cov", "pytest-jupyter[server] (>=0.6.2)", "pytest-timeout", "requests-mock", "ruamel-yaml", "sphinxcontrib-spelling", "strict-rfc3339", "werkzeug"] [[package]] -name = "jupytext" -version = "1.19.1" -description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts" +name = "jupyterlab-widgets" +version = "3.0.16" +description = "Jupyter interactive widgets for JupyterLab" optional = false -python-versions = ">=3.9" +python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "jupytext-1.19.1-py3-none-any.whl", hash = "sha256:d8975035155d034bdfde5c0c37891425314b7ea8d3a6c4b5d18c294348714cd9"}, - {file = "jupytext-1.19.1.tar.gz", hash = "sha256:82587c07e299173c70ed5e8ec7e75183edf1be289ed518bab49ad0d4e3d5f433"}, + {file = "jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8"}, + {file = "jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0"}, ] -[package.dependencies] -markdown-it-py = ">=1.0" -mdit-py-plugins = "*" -nbformat = "*" -packaging = "*" -pyyaml = "*" -tomli = {version = "*", markers = "python_version < \"3.11\""} - -[package.extras] -dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs[fs] (>=1.0)", "jupyter-server (!=2.11)", "marimo (>=0.17.6,<=0.19.4)", "nbconvert", "pre-commit", "pytest", "pytest-asyncio", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx", "sphinx-gallery (>=0.8)"] -docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"] -test = ["pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"] -test-cov = ["black", "ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-asyncio", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist"] -test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs[fs] (>=1.0)", "jupyter-server (!=2.11)", "marimo (>=0.17.6,<=0.19.4)", "nbconvert", "pre-commit", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist", "sphinx", "sphinx-gallery (>=0.8)"] -test-functional = ["black", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"] -test-integration = ["black", "ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-asyncio", "pytest-randomly", "pytest-xdist"] -test-ui = ["bash-kernel"] - [[package]] name = "lark" version = "1.3.1" @@ -2173,22 +2123,6 @@ types-paramiko = ">=3.5.0" xhell = ">=0.2.0" xonsh = ">=0.15.0" -[[package]] -name = "markdown" -version = "3.10.2" -description = "Python implementation of John Gruber's Markdown." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "markdown-3.10.2-py3-none-any.whl", hash = "sha256:e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36"}, - {file = "markdown-3.10.2.tar.gz", hash = "sha256:994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950"}, -] - -[package.extras] -docs = ["mdx_gh_links (>=0.2)", "mkdocs (>=1.6)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python] (>=0.28.3)"] -testing = ["coverage", "pyyaml"] - [[package]] name = "markdown-it-py" version = "4.0.0" @@ -2342,26 +2276,6 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] -[[package]] -name = "mdit-py-plugins" -version = "0.5.0" -description = "Collection of plugins for markdown-it-py" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "mdit_py_plugins-0.5.0-py3-none-any.whl", hash = "sha256:07a08422fc1936a5d26d146759e9155ea466e842f5ab2f7d2266dd084c8dab1f"}, - {file = "mdit_py_plugins-0.5.0.tar.gz", hash = "sha256:f4918cb50119f50446560513a8e311d574ff6aaed72606ddae6d35716fe809c6"}, -] - -[package.dependencies] -markdown-it-py = ">=2.0.0,<5.0.0" - -[package.extras] -code-style = ["pre-commit"] -rtd = ["myst-parser", "sphinx-book-theme"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - [[package]] name = "mdurl" version = "0.1.2" @@ -2374,18 +2288,6 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] -[[package]] -name = "mergedeep" -version = "1.3.4" -description = "A deep merge function for 🐍." -optional = false -python-versions = ">=3.6" -groups = ["dev"] -files = [ - {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, - {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, -] - [[package]] name = "mistune" version = "3.2.0" @@ -2401,249 +2303,6 @@ files = [ [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.11\""} -[[package]] -name = "mkdocs" -version = "1.6.1" -description = "Project documentation with Markdown." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mkdocs-1.6.1-py3-none-any.whl", hash = "sha256:db91759624d1647f3f34aa0c3f327dd2601beae39a366d6e064c03468d35c20e"}, - {file = "mkdocs-1.6.1.tar.gz", hash = "sha256:7b432f01d928c084353ab39c57282f29f92136665bdd6abf7c1ec8d822ef86f2"}, -] - -[package.dependencies] -click = ">=7.0" -colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} -ghp-import = ">=1.0" -jinja2 = ">=2.11.1" -markdown = ">=3.3.6" -markupsafe = ">=2.0.1" -mergedeep = ">=1.3.4" -mkdocs-get-deps = ">=0.2.0" -packaging = ">=20.5" -pathspec = ">=0.11.1" -pyyaml = ">=5.1" -pyyaml-env-tag = ">=0.1" -watchdog = ">=2.0" - -[package.extras] -i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4) ; platform_system == \"Windows\"", "ghp-import (==1.0)", "importlib-metadata (==4.4) ; python_version < \"3.10\"", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] - -[[package]] -name = "mkdocs-autorefs" -version = "1.4.4" -description = "Automatically link across pages in MkDocs." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mkdocs_autorefs-1.4.4-py3-none-any.whl", hash = "sha256:834ef5408d827071ad1bc69e0f39704fa34c7fc05bc8e1c72b227dfdc5c76089"}, - {file = "mkdocs_autorefs-1.4.4.tar.gz", hash = "sha256:d54a284f27a7346b9c38f1f852177940c222da508e66edc816a0fa55fc6da197"}, -] - -[package.dependencies] -Markdown = ">=3.3" -markupsafe = ">=2.0.1" -mkdocs = ">=1.1" - -[[package]] -name = "mkdocs-exclude" -version = "1.0.2" -description = "A mkdocs plugin that lets you exclude files or trees." -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "mkdocs-exclude-1.0.2.tar.gz", hash = "sha256:ba6fab3c80ddbe3fd31d3e579861fd3124513708271180a5f81846da8c7e2a51"}, -] - -[package.dependencies] -mkdocs = "*" - -[[package]] -name = "mkdocs-gen-files" -version = "0.6.0" -description = "MkDocs plugin to programmatically generate documentation pages during the build" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mkdocs_gen_files-0.6.0-py3-none-any.whl", hash = "sha256:815af15f3e2dbfda379629c1b95c02c8e6f232edf2a901186ea3b204ab1135b2"}, - {file = "mkdocs_gen_files-0.6.0.tar.gz", hash = "sha256:52022dc14dcc0451e05e54a8f5d5e7760351b6701eff816d1e9739577ec5635e"}, -] - -[package.dependencies] -mkdocs = ">=1.4.1" - -[[package]] -name = "mkdocs-get-deps" -version = "0.2.0" -description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, - {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, -] - -[package.dependencies] -mergedeep = ">=1.3.4" -platformdirs = ">=2.2.0" -pyyaml = ">=5.1" - -[[package]] -name = "mkdocs-jupyter" -version = "0.25.1" -description = "Use Jupyter in mkdocs websites" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mkdocs_jupyter-0.25.1-py3-none-any.whl", hash = "sha256:3f679a857609885d322880e72533ef5255561bbfdb13cfee2a1e92ef4d4ad8d8"}, - {file = "mkdocs_jupyter-0.25.1.tar.gz", hash = "sha256:0e9272ff4947e0ec683c92423a4bfb42a26477c103ab1a6ab8277e2dcc8f7afe"}, -] - -[package.dependencies] -ipykernel = ">6.0.0,<7.0.0" -jupytext = ">1.13.8,<2" -mkdocs = ">=1.4.0,<2" -mkdocs-material = ">9.0.0" -nbconvert = ">=7.2.9,<8" -pygments = ">2.12.0" - -[[package]] -name = "mkdocs-literate-nav" -version = "0.6.2" -description = "MkDocs plugin to specify the navigation in Markdown instead of YAML" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "mkdocs_literate_nav-0.6.2-py3-none-any.whl", hash = "sha256:0a6489a26ec7598477b56fa112056a5e3a6c15729f0214bea8a4dbc55bd5f630"}, - {file = "mkdocs_literate_nav-0.6.2.tar.gz", hash = "sha256:760e1708aa4be86af81a2b56e82c739d5a8388a0eab1517ecfd8e5aa40810a75"}, -] - -[package.dependencies] -mkdocs = ">=1.4.1" - -[[package]] -name = "mkdocs-macros-plugin" -version = "1.5.0" -description = "Unleash the power of MkDocs with macros and variables" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mkdocs_macros_plugin-1.5.0-py3-none-any.whl", hash = "sha256:c10fabd812bf50f9170609d0ed518e54f1f0e12c334ac29141723a83c881dd6f"}, - {file = "mkdocs_macros_plugin-1.5.0.tar.gz", hash = "sha256:12aa45ce7ecb7a445c66b9f649f3dd05e9b92e8af6bc65e4acd91d26f878c01f"}, -] - -[package.dependencies] -hjson = "*" -jinja2 = "*" -mkdocs = ">=0.17" -packaging = "*" -pathspec = "*" -python-dateutil = "*" -pyyaml = "*" -requests = "*" -super-collections = ">=0.6.2" -termcolor = "*" - -[package.extras] -doc = ["mkdocs-mermaid2-plugin"] -test = ["mkdocs-d2-plugin", "mkdocs-include-markdown-plugin", "mkdocs-macros-test", "mkdocs-material (>=6.2)", "mkdocs-test (>=0.6.0)", "pytest"] - -[[package]] -name = "mkdocs-material" -version = "9.7.4" -description = "Documentation that simply works" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mkdocs_material-9.7.4-py3-none-any.whl", hash = "sha256:6549ad95e4d130ed5099759dfa76ea34c593eefdb9c18c97273605518e99cfbf"}, - {file = "mkdocs_material-9.7.4.tar.gz", hash = "sha256:711b0ee63aca9a8c7124d4c73e83a25aa996e27e814767c3a3967df1b9e56f32"}, -] - -[package.dependencies] -babel = ">=2.10" -backrefs = ">=5.7.post1" -colorama = ">=0.4" -jinja2 = ">=3.1" -markdown = ">=3.2" -mkdocs = ">=1.6" -mkdocs-material-extensions = ">=1.3" -paginate = ">=0.5" -pygments = ">=2.16" -pymdown-extensions = ">=10.2" -requests = ">=2.30" - -[package.extras] -git = ["mkdocs-git-committers-plugin-2 (>=1.1)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4)"] -imaging = ["cairosvg (>=2.6)", "pillow (>=10.2)"] -recommended = ["mkdocs-minify-plugin (>=0.7)", "mkdocs-redirects (>=1.2)", "mkdocs-rss-plugin (>=1.6)"] - -[[package]] -name = "mkdocs-material-extensions" -version = "1.3.1" -description = "Extension pack for Python Markdown and MkDocs Material." -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, - {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, -] - -[[package]] -name = "mkdocstrings" -version = "1.0.3" -description = "Automatic documentation from sources, for MkDocs." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "mkdocstrings-1.0.3-py3-none-any.whl", hash = "sha256:0d66d18430c2201dc7fe85134277382baaa15e6b30979f3f3bdbabd6dbdb6046"}, - {file = "mkdocstrings-1.0.3.tar.gz", hash = "sha256:ab670f55040722b49bb45865b2e93b824450fb4aef638b00d7acb493a9020434"}, -] - -[package.dependencies] -Jinja2 = ">=3.1" -Markdown = ">=3.6" -MarkupSafe = ">=1.1" -mkdocs = ">=1.6" -mkdocs-autorefs = ">=1.4" -mkdocstrings-python = {version = ">=1.16.2", optional = true, markers = "extra == \"python\""} -pymdown-extensions = ">=6.3" - -[package.extras] -crystal = ["mkdocstrings-crystal (>=0.3.4)"] -python = ["mkdocstrings-python (>=1.16.2)"] -python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] - -[[package]] -name = "mkdocstrings-python" -version = "1.19.0" -description = "A Python handler for mkdocstrings." -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "mkdocstrings_python-1.19.0-py3-none-any.whl", hash = "sha256:395c1032af8f005234170575cc0c5d4d20980846623b623b35594281be4a3059"}, - {file = "mkdocstrings_python-1.19.0.tar.gz", hash = "sha256:917aac66cf121243c11db5b89f66b0ded6c53ec0de5318ff5e22424eb2f2e57c"}, -] - -[package.dependencies] -griffe = ">=1.13" -mkdocs-autorefs = ">=1.4" -mkdocstrings = ">=0.30" -typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} - [[package]] name = "mypy" version = "1.19.1" @@ -2843,6 +2502,30 @@ files = [ {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, ] +[[package]] +name = "notebook" +version = "7.5.4" +description = "Jupyter Notebook - A web-based notebook environment for interactive computing" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "notebook-7.5.4-py3-none-any.whl", hash = "sha256:860e31782b3d3a25ca0819ff039f5cf77845d1bf30c78ef9528b88b25e0a9850"}, + {file = "notebook-7.5.4.tar.gz", hash = "sha256:b928b2ba22cb63aa83df2e0e76fe3697950a0c1c4a41b84ebccf1972b1bb5771"}, +] + +[package.dependencies] +jupyter-server = ">=2.4.0,<3" +jupyterlab = ">=4.5.5,<4.6" +jupyterlab-server = ">=2.28.0,<3" +notebook-shim = ">=0.2,<0.3" +tornado = ">=6.2.0" + +[package.extras] +dev = ["hatch", "pre-commit"] +docs = ["myst-parser", "nbsphinx", "pydata-sphinx-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["importlib-resources (>=5.0) ; python_version < \"3.10\"", "ipykernel", "jupyter-server[test] (>=2.4.0,<3)", "jupyterlab-server[test] (>=2.28.0,<3)", "nbval", "pytest (>=7.0)", "pytest-console-scripts", "pytest-timeout", "pytest-tornasync", "requests"] + [[package]] name = "notebook-shim" version = "0.2.4" @@ -2886,22 +2569,6 @@ files = [ {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, ] -[[package]] -name = "paginate" -version = "0.5.7" -description = "Divides large result sets into pages for easier browsing" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "paginate-0.5.7-py2.py3-none-any.whl", hash = "sha256:b885e2af73abcf01d9559fd5216b57ef722f8c42affbb63942377668e35c7591"}, - {file = "paginate-0.5.7.tar.gz", hash = "sha256:22bd083ab41e1a8b4f3690544afb2c60c25e5c9a63a30fa2f483f6c60c8e5945"}, -] - -[package.extras] -dev = ["pytest", "tox"] -lint = ["black"] - [[package]] name = "pandocfilters" version = "1.5.1" @@ -3268,25 +2935,6 @@ xhell = ">=0.2.1" type = "directory" url = "packages/irx" -[[package]] -name = "pymdown-extensions" -version = "10.21" -description = "Extension pack for Python Markdown." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pymdown_extensions-10.21-py3-none-any.whl", hash = "sha256:91b879f9f864d49794c2d9534372b10150e6141096c3908a455e45ca72ad9d3f"}, - {file = "pymdown_extensions-10.21.tar.gz", hash = "sha256:39f4a020f40773f6b2ff31d2cd2546c2c04d0a6498c31d9c688d2be07e1767d5"}, -] - -[package.dependencies] -markdown = ">=3.6" -pyyaml = "*" - -[package.extras] -extra = ["pygments (>=2.19.1)"] - [[package]] name = "pynacl" version = "1.6.2" @@ -3584,21 +3232,6 @@ files = [ {file = "pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"}, ] -[[package]] -name = "pyyaml-env-tag" -version = "1.1" -description = "A custom YAML tag for referencing environment variables in YAML files." -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "pyyaml_env_tag-1.1-py3-none-any.whl", hash = "sha256:17109e1a528561e32f026364712fee1264bc2ea6715120891174ed1b980d2e04"}, - {file = "pyyaml_env_tag-1.1.tar.gz", hash = "sha256:2eb38b75a2d21ee0475d6d97ec19c63287a7e140231e4214969d0eac923cd7ff"}, -] - -[package.dependencies] -pyyaml = "*" - [[package]] name = "pyzmq" version = "27.1.0" @@ -3704,6 +3337,22 @@ files = [ [package.dependencies] cffi = {version = "*", markers = "implementation_name == \"pypy\""} +[[package]] +name = "quarto-cli" +version = "1.9.37" +description = "Open-source scientific and technical publishing system built on Pandoc." +optional = false +python-versions = "*" +groups = ["dev"] +files = [ + {file = "quarto_cli-1.9.37.tar.gz", hash = "sha256:bc2047e9968684e2ce98a72b7fa986761bfcd64b314b1660ef10e0469346f56b"}, +] + +[package.dependencies] +jupyter = "*" +nbclient = "*" +wheel = "*" + [[package]] name = "rapidfuzz" version = "3.14.3" @@ -4276,39 +3925,6 @@ files = [ {file = "stevedore-5.7.0.tar.gz", hash = "sha256:31dd6fe6b3cbe921e21dcefabc9a5f1cf848cf538a1f27543721b8ca09948aa3"}, ] -[[package]] -name = "super-collections" -version = "0.6.2" -description = "file: README.md" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "super_collections-0.6.2-py3-none-any.whl", hash = "sha256:291b74d26299e9051d69ad9d89e61b07b6646f86a57a2f5ab3063d206eee9c56"}, - {file = "super_collections-0.6.2.tar.gz", hash = "sha256:0c8d8abacd9fad2c7c1c715f036c29f5db213f8cac65f24d45ecba12b4da187a"}, -] - -[package.dependencies] -hjson = "*" - -[package.extras] -test = ["pytest (>=7.0)", "pyyaml", "rich"] - -[[package]] -name = "termcolor" -version = "3.3.0" -description = "ANSI color formatting for output in terminal" -optional = false -python-versions = ">=3.10" -groups = ["dev"] -files = [ - {file = "termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5"}, - {file = "termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5"}, -] - -[package.extras] -tests = ["pytest", "pytest-cov"] - [[package]] name = "terminado" version = "0.18.1" @@ -4630,49 +4246,6 @@ files = [ [package.dependencies] tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -[[package]] -name = "watchdog" -version = "6.0.0" -description = "Filesystem events monitoring" -optional = false -python-versions = ">=3.9" -groups = ["dev"] -files = [ - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, - {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, - {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, - {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, - {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, - {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, - {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, - {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, - {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, - {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, - {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, - {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, - {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, -] - -[package.extras] -watchmedo = ["PyYAML (>=3.10)"] - [[package]] name = "wcwidth" version = "0.6.0" @@ -4726,6 +4299,33 @@ docs = ["Sphinx (>=6.0)", "myst-parser (>=2.0.0)", "sphinx_rtd_theme (>=1.1.0)"] optional = ["python-socks", "wsaccel"] test = ["pytest", "websockets"] +[[package]] +name = "wheel" +version = "0.47.0" +description = "Command line tool for manipulating wheel files" +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "wheel-0.47.0-py3-none-any.whl", hash = "sha256:212281cab4dff978f6cedd499cd893e1f620791ca6ff7107cf270781e587eced"}, + {file = "wheel-0.47.0.tar.gz", hash = "sha256:cc72bd1009ba0cf63922e28f94d9d83b920aa2bb28f798a31d0691b02fa3c9b3"}, +] + +[package.dependencies] +packaging = ">=24.0" + +[[package]] +name = "widgetsnbextension" +version = "4.0.15" +description = "Jupyter interactive widgets for Jupyter Notebook" +optional = false +python-versions = ">=3.7" +groups = ["dev"] +files = [ + {file = "widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366"}, + {file = "widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9"}, +] + [[package]] name = "xhell" version = "0.2.1" @@ -4800,4 +4400,4 @@ test = ["coverage (>=5.3.1)", "prompt-toolkit (>=3.0.29)", "pygments (>=2.2)", " [metadata] lock-version = "2.1" python-versions = ">=3.10,<4" -content-hash = "6021b91451462cc5c7a9babcbd99271b38d60056cfc127d64458eeca88989b35" +content-hash = "2a77b8f282816c0fdd9cbbc4ed77160800766db0747081d50540dcb06d10ef20" diff --git a/pyproject.toml b/pyproject.toml index acd1305..a8144ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,15 +35,7 @@ vulture = ">=2.9.1" mccabe = ">=0.6.1" ipykernel = ">=6.0.0" ipython = ">=7.0.0" -mkdocs = ">=1.3,<2" -mkdocs-exclude = ">=1.0.2" -mkdocs-jupyter = ">=0.24.7" -mkdocs-literate-nav = ">=0.4.1" -mkdocs-macros-plugin = ">=0.6.3" -mkdocs-material = ">=8" -mkdocstrings = {version=">=0.19.0", extras=["python"]} -mkdocstrings-python = "<2" -mkdocs-gen-files = ">=0.5.0" +quarto-cli = ">=1.9.0" jupyterlab = ">=4.0.7" makim = "1.27.0" nbmake = ">=1.5.3" diff --git a/scripts/gen_api_docs.py b/scripts/gen_api_docs.py new file mode 100644 index 0000000..d0bb970 --- /dev/null +++ b/scripts/gen_api_docs.py @@ -0,0 +1,484 @@ +""" +title: Generate Quarto API reference pages from Python source. +summary: Build lightweight Markdown API pages without site-generator plugins. +""" + +from __future__ import annotations + +import ast +import shutil +import textwrap + +from dataclasses import dataclass +from pathlib import Path +from typing import TypeGuard + +ROOT = Path(__file__).resolve().parent.parent +DOCS_DIR = ROOT / "docs" +API_DIR = DOCS_DIR / "api" +SOURCE_ROOTS = ( + ROOT / "packages" / "arx" / "src", + ROOT / "packages" / "astx" / "src", + ROOT / "packages" / "irx" / "src", +) +PRIVATE_PREFIX = "_" + + +@dataclass(frozen=True) +class FunctionDoc: + """ + title: Documentation data for one function-like symbol. + attributes: + name: + type: str + signature: + type: str + docstring: + type: str + """ + + name: str + signature: str + docstring: str + + +@dataclass(frozen=True) +class ClassDoc: + """ + title: Documentation data for one class symbol. + attributes: + name: + type: str + bases: + type: tuple[str, Ellipsis] + docstring: + type: str + methods: + type: tuple[FunctionDoc, Ellipsis] + """ + + name: str + bases: tuple[str, ...] + docstring: str + methods: tuple[FunctionDoc, ...] + + +@dataclass(frozen=True) +class ModuleDoc: + """ + title: Documentation data for one Python module. + attributes: + name: + type: str + source_path: + type: Path + docstring: + type: str + classes: + type: tuple[ClassDoc, Ellipsis] + functions: + type: tuple[FunctionDoc, Ellipsis] + """ + + name: str + source_path: Path + docstring: str + classes: tuple[ClassDoc, ...] + functions: tuple[FunctionDoc, ...] + + +class ApiDocError(Exception): + """ + title: Raised when API documentation cannot be generated. + """ + + +def main() -> None: + """ + title: Generate the API documentation tree. + """ + modules = list(iter_modules()) + write_api_tree(modules) + + +def iter_modules() -> list[ModuleDoc]: + """ + title: Collect documentation data for all public Python modules. + returns: + type: list[ModuleDoc] + """ + modules: list[ModuleDoc] = [] + for source_root in SOURCE_ROOTS: + for path in sorted(source_root.rglob("*.py")): + if should_skip(path): + continue + modules.append(parse_module(source_root, path)) + return modules + + +def should_skip(path: Path) -> bool: + """ + title: Return whether a Python file should be excluded from API docs. + parameters: + path: + type: Path + returns: + type: bool + """ + return path.name.startswith(PRIVATE_PREFIX) and path.name != "__init__.py" + + +def parse_module(source_root: Path, path: Path) -> ModuleDoc: + """ + title: Parse public API documentation from one source file. + parameters: + source_root: + type: Path + path: + type: Path + returns: + type: ModuleDoc + """ + source = path.read_text(encoding="utf-8") + try: + tree = ast.parse(source, filename=str(path)) + except SyntaxError as exc: + msg = f"Cannot parse {path}: {exc}" + raise ApiDocError(msg) from exc + + module_name = module_name_for(source_root, path) + classes: list[ClassDoc] = [] + functions: list[FunctionDoc] = [] + + for node in tree.body: + if isinstance(node, ast.ClassDef) and is_public(node.name): + classes.append(class_doc(node)) + continue + if is_public_function(node): + functions.append(function_doc(node)) + + return ModuleDoc( + name=module_name, + source_path=path.relative_to(ROOT), + docstring=clean_docstring(ast.get_docstring(tree)), + classes=tuple(classes), + functions=tuple(functions), + ) + + +def module_name_for(source_root: Path, path: Path) -> str: + """ + title: Convert a Python path to its importable module name. + parameters: + source_root: + type: Path + path: + type: Path + returns: + type: str + """ + module_path = path.relative_to(source_root).with_suffix("") + parts = module_path.parts + if parts[-1] == "__init__": + parts = parts[:-1] + return ".".join(parts) + + +def class_doc(node: ast.ClassDef) -> ClassDoc: + """ + title: Build documentation for a class definition. + parameters: + node: + type: ast.ClassDef + returns: + type: ClassDoc + """ + methods: list[FunctionDoc] = [] + for item in node.body: + if is_public_function(item): + methods.append(function_doc(item)) + + return ClassDoc( + name=node.name, + bases=tuple(ast.unparse(base) for base in node.bases), + docstring=clean_docstring(ast.get_docstring(node)), + methods=tuple(methods), + ) + + +def function_doc(node: ast.FunctionDef | ast.AsyncFunctionDef) -> FunctionDoc: + """ + title: Build documentation for a function or method definition. + parameters: + node: + type: ast.FunctionDef | ast.AsyncFunctionDef + returns: + type: FunctionDoc + """ + return FunctionDoc( + name=node.name, + signature=signature_for(node), + docstring=clean_docstring(ast.get_docstring(node)), + ) + + +def signature_for(node: ast.FunctionDef | ast.AsyncFunctionDef) -> str: + """ + title: Return a display signature for a function-like AST node. + parameters: + node: + type: ast.FunctionDef | ast.AsyncFunctionDef + returns: + type: str + """ + arguments = ast.unparse(node.args) + returns = "" + if node.returns is not None: + returns = f" -> {ast.unparse(node.returns)}" + prefix = "async " if isinstance(node, ast.AsyncFunctionDef) else "" + return f"{prefix}{node.name}({arguments}){returns}" + + +def clean_docstring(docstring: str | None) -> str: + """ + title: Normalize one Python docstring for Markdown output. + parameters: + docstring: + type: str | None + returns: + type: str + """ + if docstring is None: + return "" + return textwrap.dedent(docstring).strip() + + +def is_public(name: str) -> bool: + """ + title: Return whether a symbol name is part of public documentation. + parameters: + name: + type: str + returns: + type: bool + """ + return not name.startswith(PRIVATE_PREFIX) + + +def is_public_function( + node: ast.stmt, +) -> TypeGuard[ast.FunctionDef | ast.AsyncFunctionDef]: + """ + title: Return whether a statement is a public function definition. + parameters: + node: + type: ast.stmt + returns: + type: TypeGuard[ast.FunctionDef | ast.AsyncFunctionDef] + """ + if not isinstance(node, ast.FunctionDef | ast.AsyncFunctionDef): + return False + return is_public(node.name) + + +def write_api_tree(modules: list[ModuleDoc]) -> None: + """ + title: Write generated API Markdown pages under ``docs/api``. + parameters: + modules: + type: list[ModuleDoc] + """ + if API_DIR.exists(): + shutil.rmtree(API_DIR) + API_DIR.mkdir(parents=True) + + packages: dict[str, list[ModuleDoc]] = {"arx": [], "astx": [], "irx": []} + for module in modules: + package = module.name.split(".", maxsplit=1)[0] + packages.setdefault(package, []).append(module) + write_module_page(module) + + write_api_index(packages) + for package, package_modules in sorted(packages.items()): + write_package_index(package, package_modules) + + +def write_api_index(packages: dict[str, list[ModuleDoc]]) -> None: + """ + title: Write the top-level API index page. + parameters: + packages: + type: dict[str, list[ModuleDoc]] + """ + lines = [ + "---", + "title: API Docs", + "---", + "", + "# API Docs", + "", + "Generated from the Python sources for Arx, ASTx, and IRx.", + "", + ] + for package in sorted(packages): + if not packages[package]: + continue + lines.append(f"- [{package}](./{package}/index.md)") + write_lines(API_DIR / "index.md", lines) + + +def write_package_index(package: str, modules: list[ModuleDoc]) -> None: + """ + title: Write an index page for one package API section. + parameters: + package: + type: str + modules: + type: list[ModuleDoc] + """ + package_dir = API_DIR / package + package_dir.mkdir(parents=True, exist_ok=True) + lines = [ + "---", + f"title: {package} API", + "---", + "", + f"# `{package}` API", + "", + ] + for module in sorted(modules, key=lambda item: item.name): + href = module_href_from_package_index(package, module) + lines.append(f"- [`{module.name}`]({href})") + write_lines(package_dir / "index.md", lines) + + +def write_module_page(module: ModuleDoc) -> None: + """ + title: Write one module API page. + parameters: + module: + type: ModuleDoc + """ + target = API_DIR / Path(*module.name.split(".")).with_suffix(".md") + target.parent.mkdir(parents=True, exist_ok=True) + + lines = [ + "---", + f"title: {module.name}", + "---", + "", + f"# `{module.name}`", + "", + f"Source: `{module.source_path.as_posix()}`", + "", + ] + append_docstring(lines, module.docstring) + append_functions(lines, module.functions) + append_classes(lines, module.classes) + write_lines(target, lines) + + +def append_functions( + lines: list[str], + functions: tuple[FunctionDoc, ...], +) -> None: + """ + title: Append function documentation sections. + parameters: + lines: + type: list[str] + functions: + type: tuple[FunctionDoc, Ellipsis] + """ + if not functions: + return + lines.extend(["## Functions", ""]) + for item in functions: + lines.extend([f"### `{item.signature}`", ""]) + append_docstring(lines, item.docstring) + + +def append_classes(lines: list[str], classes: tuple[ClassDoc, ...]) -> None: + """ + title: Append class documentation sections. + parameters: + lines: + type: list[str] + classes: + type: tuple[ClassDoc, Ellipsis] + """ + if not classes: + return + lines.extend(["## Classes", ""]) + for item in classes: + title = item.name + if item.bases: + title = f"{item.name}({', '.join(item.bases)})" + lines.extend([f"### `{title}`", ""]) + append_docstring(lines, item.docstring) + append_methods(lines, item.methods) + + +def append_methods(lines: list[str], methods: tuple[FunctionDoc, ...]) -> None: + """ + title: Append method documentation for one class. + parameters: + lines: + type: list[str] + methods: + type: tuple[FunctionDoc, Ellipsis] + """ + if not methods: + return + lines.extend(["#### Methods", ""]) + for item in methods: + lines.extend([f"##### `{item.signature}`", ""]) + append_docstring(lines, item.docstring) + + +def append_docstring(lines: list[str], docstring: str) -> None: + """ + title: Append a normalized docstring as Markdown. + parameters: + lines: + type: list[str] + docstring: + type: str + """ + if not docstring: + lines.extend(["_No docstring available._", ""]) + return + lines.extend(["```yaml", docstring, "```", ""]) + + +def module_href_from_package_index(package: str, module: ModuleDoc) -> str: + """ + title: Return the relative link from a package index to a module page. + parameters: + package: + type: str + module: + type: ModuleDoc + returns: + type: str + """ + parts = module.name.split(".") + if parts == [package]: + return f"../{package}.md" + return "./" + "/".join(parts[1:]) + ".md" + + +def write_lines(path: Path, lines: list[str]) -> None: + """ + title: Write Markdown lines to a file with a trailing newline. + parameters: + path: + type: Path + lines: + type: list[str] + """ + path.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8") + + +if __name__ == "__main__": + main() diff --git a/scripts/gen_ref_nav.py b/scripts/gen_ref_nav.py deleted file mode 100644 index 89f436d..0000000 --- a/scripts/gen_ref_nav.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -title: Generate the code reference pages and navigation. -references: - - >- - https://github.com/mkdocstrings/mkdocstrings/blob/main/scripts/gen_ref_nav. - py -""" - -from pathlib import Path - -import mkdocs_gen_files - -nav = mkdocs_gen_files.Nav() -mod_symbol = ( - '' -) - -root = Path(__file__).parent.parent -source_roots = ( - root / "packages" / "arx" / "src", - root / "packages" / "astx" / "src", - root / "packages" / "irx" / "src", -) - -for src in source_roots: - for path in sorted(src.rglob("*.py")): - module_path = path.relative_to(src).with_suffix("") - doc_path = module_path.with_suffix(".md") - full_doc_path = Path("api", 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") - elif parts[-1].startswith("_"): - 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"::: {ident}") - - mkdocs_gen_files.set_edit_path( - full_doc_path, ".." / path.relative_to(root) - ) - -with mkdocs_gen_files.open("api/SUMMARY.md", "w") as nav_file: - nav_file.writelines(nav.build_literate_nav())