diff --git a/.github/workflows/deploy-gh-pages.yml b/.github/workflows/deploy-gh-pages.yml index ee91ff9..faa554a 100644 --- a/.github/workflows/deploy-gh-pages.yml +++ b/.github/workflows/deploy-gh-pages.yml @@ -48,6 +48,15 @@ jobs: - name: Install docs dependencies run: uv sync --locked --no-default-groups --group docs + # Same cache as the docs check: social cards and the external assets the + # privacy plugin downloads, so a deploy does not re-fetch them. + - name: Restore social card and external asset cache + uses: actions/cache@v4 + with: + path: .cache + key: mkdocs-material-${{ hashFiles('mkdocs.yml', 'docs/**') }} + restore-keys: mkdocs-material- + - name: Deploy docs as dev if: ${{ github.ref == 'refs/heads/main' }} run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bea0e70..e35cbf3 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,5 +28,16 @@ jobs: - name: Install docs dependencies run: uv sync --locked --no-default-groups --group docs + # The social plugin renders a card per page and the privacy plugin + # downloads the fonts and CDN scripts the pages reference. Both write to + # .cache. Without it every build re-fetches them, and a strict build + # turns a single failed download into a build failure. + - name: Restore social card and external asset cache + uses: actions/cache@v4 + with: + path: .cache + key: mkdocs-material-${{ hashFiles('mkdocs.yml', 'docs/**') }} + restore-keys: mkdocs-material- + - name: Build documentation (strict, execute notebooks) run: uv run mkdocs build --strict diff --git a/mkdocs.yml b/mkdocs.yml index 0355682..baab2a1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -99,6 +99,14 @@ plugins: allow_errors: False include_requirejs: True - search: + # Both docs workflows check out with fetch-depth: 0, so the full history the + # plugin needs to date a page is available. + - git-revision-date-localized: + type: date + enable_creation_date: true + # Pages the plugin cannot date (anything untracked at build time) fall + # back to the build date instead of failing the strict build. + fallback_to_build_date: true - mike: alias_type: redirect redirect_template: null @@ -107,6 +115,12 @@ plugins: version_selector: true css_dir: css javascript_dir: js + # Renders a preview card per page for link unfurling in chat apps and social + # networks. Card URLs are absolute, built from site_url, which mike rewrites + # to include the version prefix during a versioned deploy. + - social: + cards_layout_options: + background_color: "#3f51b5" # matches the indigo primary # Must come after mkdocstrings and mkdocs-jupyter: this plugin converts the # rendered HTML back to Markdown, so it needs their output to already exist. # Otherwise the API pages would export as bare `::: ikpykit.X` directives. @@ -133,6 +147,32 @@ plugins: - faq/table-of-contents.md - contributing/contribution.md - authors/authors.md + # Downloads the external assets the pages reference (Google Fonts, the CDN + # copy of require.js that mkdocs-jupyter pulls in) and serves them from this + # site instead, so a visitor's browser makes no third-party requests for them. + # Listed last because it rewrites the built output. + - privacy: + assets_exclude: + # Google Analytics has to load from Google to work at all, so + # self-hosting it would only break the tag. The cookie consent banner + # in `extra.consent` stays for that reason. + - www.googletagmanager.com/* + # The README badges are rendered on request by their providers. A local + # copy would freeze the download counts, coverage and build status at + # the moment the docs were built. + - img.shields.io/* + - static.pepy.tech/* + - codecov.io/* + - www.repostatus.org/* + - github.com/*/badge.svg + # The theme bundle names this URL so it can lazy-load Mermaid for + # diagrams. This site defines none, so vendoring it would add 3.4 MB to + # every deployed version for a file no page ever requests. + - unpkg.com/mermaid* + # A Font Awesome kit is a loader, not the icons: the config it carries + # points at ka-f.fontawesome.com, so a local copy still reaches out to + # Font Awesome and only adds a way for the kit to break. + - kit.fontawesome.com/* theme: name: material custom_dir: docs/overrides diff --git a/pyproject.toml b/pyproject.toml index 8633ffa..6164ba6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,8 +94,13 @@ docs = [ "matplotlib>=3.9.0", "mike==2.2.0", "mkdocs==1.6.1", + "mkdocs-git-revision-date-localized-plugin==1.5.3", "mkdocs-jupyter==0.26.3", "mkdocs-llmstxt==0.5.0", + # The theme was previously only reached through mkdocs-jupyter. It is a + # direct requirement of this site, and the imaging extra (cairosvg, pillow) + # is what the built-in social plugin renders cards with. + "mkdocs-material[imaging]==9.7.7", "mkdocstrings==1.0.6", "mkdocstrings-python==2.0.5", "notebook==7.6.2", diff --git a/uv.lock b/uv.lock index 436e0de..a0bf276 100644 --- a/uv.lock +++ b/uv.lock @@ -209,6 +209,34 @@ css = [ { name = "tinycss2" }, ] +[[package]] +name = "cairocffi" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/c5/1a4dc131459e68a173cbdab5fad6b524f53f9c1ef7861b7698e998b837cc/cairocffi-1.7.1.tar.gz", hash = "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b", size = 88096, upload-time = "2024-06-18T10:56:06.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d8/ba13451aa6b745c49536e87b6bf8f629b950e84bd0e8308f7dc6883b67e2/cairocffi-1.7.1-py3-none-any.whl", hash = "sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f", size = 75611, upload-time = "2024-06-18T10:55:59.489Z" }, +] + +[[package]] +name = "cairosvg" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cairocffi" }, + { name = "cssselect2" }, + { name = "defusedxml" }, + { name = "pillow" }, + { name = "tinycss2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/07/e8412a13019b3f737972dea23a2c61ca42becafc16c9338f4ca7a0caa993/cairosvg-2.9.0.tar.gz", hash = "sha256:1debb00cd2da11350d8b6f5ceb739f1b539196d71d5cf5eb7363dbd1bfbc8dc5", size = 40877, upload-time = "2026-03-13T15:42:00.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/e0/5011747466414c12cac8a8df77aa235068669a6a5a5df301a96209db6054/cairosvg-2.9.0-py3-none-any.whl", hash = "sha256:4b82d07d145377dffdfc19d9791bd5fb65539bb4da0adecf0bdbd9cd4ffd7c68", size = 45962, upload-time = "2026-03-14T13:56:33.512Z" }, +] + [[package]] name = "certifi" version = "2025.11.12" @@ -574,6 +602,19 @@ toml = [ { name = "tomli", marker = "python_full_version <= '3.11'" }, ] +[[package]] +name = "cssselect2" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tinycss2" }, + { name = "webencodings" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/20/92eaa6b0aec7189fa4b75c890640e076e9e793095721db69c5c81142c2e1/cssselect2-0.9.0.tar.gz", hash = "sha256:759aa22c216326356f65e62e791d66160a0f9c91d1424e8d8adc5e74dddfc6fb", size = 35595, upload-time = "2026-02-12T17:16:39.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl", hash = "sha256:6a99e5f91f9a016a304dd929b0966ca464bcfda15177b6fb4a118fc0fb5d9563", size = 15453, upload-time = "2026-02-12T17:16:38.317Z" }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -732,6 +773,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/ec/67fbef5d497f86283db54c22eec6f6140243aae73265799baaaa19cd17fb/ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619", size = 11034, upload-time = "2022-05-02T15:47:14.552Z" }, ] +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.59" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/dc/126b28e76b24a9268ba931ad3e012f71ebdadf62fd9f17758f7074bb0b20/gitpython-3.1.59.tar.gz", hash = "sha256:0a1475cfdc38a5bfba1a3e9a4a9da52a39749ecec322b772915c019f94e5b7e4", size = 230445, upload-time = "2026-08-10T12:03:20.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/ed/ae57eb7d344f43f87b74b3a281ead6ec7d6394eef72a7b1dcb28dd089550/gitpython-3.1.59-py3-none-any.whl", hash = "sha256:67a82f537384578643624c8b2c531938a9b82be431663e575dcf638526631d4c", size = 220996, upload-time = "2026-08-10T12:03:18.804Z" }, +] + [[package]] name = "griffelib" version = "2.1.0" @@ -819,8 +884,10 @@ docs = [ { name = "matplotlib" }, { name = "mike" }, { name = "mkdocs" }, + { name = "mkdocs-git-revision-date-localized-plugin" }, { name = "mkdocs-jupyter" }, { name = "mkdocs-llmstxt" }, + { name = "mkdocs-material", extra = ["imaging"] }, { name = "mkdocstrings" }, { name = "mkdocstrings-python" }, { name = "notebook" }, @@ -852,8 +919,10 @@ docs = [ { name = "matplotlib", specifier = ">=3.9.0" }, { name = "mike", specifier = "==2.2.0" }, { name = "mkdocs", specifier = "==1.6.1" }, + { name = "mkdocs-git-revision-date-localized-plugin", specifier = "==1.5.3" }, { name = "mkdocs-jupyter", specifier = "==0.26.3" }, { name = "mkdocs-llmstxt", specifier = "==0.5.0" }, + { name = "mkdocs-material", extras = ["imaging"], specifier = "==9.7.7" }, { name = "mkdocstrings", specifier = "==1.0.6" }, { name = "mkdocstrings-python", specifier = "==2.0.5" }, { name = "notebook", specifier = "==7.6.2" }, @@ -1679,6 +1748,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9f/d4/029f984e8d3f3b6b726bd33cafc473b75e9e44c0f7e80a5b29abc466bdea/mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134", size = 9521, upload-time = "2023-11-20T17:51:08.587Z" }, ] +[[package]] +name = "mkdocs-git-revision-date-localized-plugin" +version = "1.5.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "babel" }, + { name = "gitpython" }, + { name = "mkdocs" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/99/8067eb7d1652767ee8e5474010647dd5a8e464e0ca8c783b5cac135a2043/mkdocs_git_revision_date_localized_plugin-1.5.3.tar.gz", hash = "sha256:873444b54cab4d47c69bd6e85da05ef5fbe81fee27e64508114c46a0e4f81e37", size = 451961, upload-time = "2026-06-01T08:32:09.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/d0/cbe85158dc091219fd5134bf6d724d30b1f2005ee1d0dabaaa41416bee78/mkdocs_git_revision_date_localized_plugin-1.5.3-py3-none-any.whl", hash = "sha256:cd96e432de6a7e59b31c7041574b22f84179c8636835419ff458877ecfaaaf05", size = 26156, upload-time = "2026-06-01T08:32:07.765Z" }, +] + [[package]] name = "mkdocs-jupyter" version = "0.26.3" @@ -1713,7 +1797,7 @@ wheels = [ [[package]] name = "mkdocs-material" -version = "9.7.0" +version = "9.7.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel" }, @@ -1728,9 +1812,15 @@ dependencies = [ { name = "pymdown-extensions" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/3b/111b84cd6ff28d9e955b5f799ef217a17bc1684ac346af333e6100e413cb/mkdocs_material-9.7.0.tar.gz", hash = "sha256:602b359844e906ee402b7ed9640340cf8a474420d02d8891451733b6b02314ec", size = 4094546, upload-time = "2025-11-11T08:49:09.73Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/cd/c05d3a530ba7934f144fb45f7203cd236adc25c7bdcc34673d202f4b0278/mkdocs_material-9.7.7.tar.gz", hash = "sha256:c0649c065b1b0512d60aad8c10f947f8e455284475239b364b610f2deb4d0855", size = 4097923, upload-time = "2026-07-17T16:21:33.156Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/87/eefe8d5e764f4cf50ed91b943f8e8f96b5efd65489d8303b7a36e2e79834/mkdocs_material-9.7.0-py3-none-any.whl", hash = "sha256:da2866ea53601125ff5baa8aa06404c6e07af3c5ce3d5de95e3b52b80b442887", size = 9283770, upload-time = "2025-11-11T08:49:06.26Z" }, + { url = "https://files.pythonhosted.org/packages/ad/21/17c1bc9e6f47c972ad66fb2ac2568f99f90f1207eeb6fc3b34d094dba7b5/mkdocs_material-9.7.7-py3-none-any.whl", hash = "sha256:8ea9bb1737a5b524a5f9dcf2e1b4ebda8274ae3008aa7845720a97083bef708f", size = 9305438, upload-time = "2026-07-17T16:21:30.017Z" }, +] + +[package.optional-dependencies] +imaging = [ + { name = "cairosvg" }, + { name = "pillow" }, ] [[package]] @@ -2939,6 +3029,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] +[[package]] +name = "smmap" +version = "5.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" }, +] + [[package]] name = "sniffio" version = "1.3.1"