Skip to content

chore(deps): unpin mkdocs-material, require click>=8.4 for docs - #10333

Merged
mscolnick merged 2 commits into
marimo-team:mainfrom
tschm:bump-mkdocs-material
Jul 29, 2026
Merged

chore(deps): unpin mkdocs-material, require click>=8.4 for docs#10333
mscolnick merged 2 commits into
marimo-team:mainfrom
tschm:bump-mkdocs-material

Conversation

@tschm

@tschm tschm commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

This pull request was authored by a coding agent.

📝 Summary

Closes #10334

The docs group pinned mkdocs-material==9.6.20 with:

# Live reloading broken in >= 9.6.21: https://github.com/squidfunk/mkdocs-material/issues/8478
"mkdocs-material==9.6.20",

That pin treats a symptom. 9.6.20 is just the last release that capped click<8.2.2 — the incidental click cap was doing the work, not anything about the theme. mkdocs-material dropped that cap in 9.6.21, which is why live reload appeared to break there.

The actual bug is in click. MkDocs declares --no-livereload / --livereload as a feature switch group — two flag_value options sharing one parameter name, where only the second carries default=True:

@click.option('--no-livereload', 'livereload', flag_value=False, help=no_reload_help)
@click.option('--livereload', 'livereload', flag_value=True, default=True, hidden=True)

click 8.3.0 started dropping that explicit default when a sibling without one was declared first, so mkdocs serve silently came up with live reload off. click 8.4.0 fixed it, per its changelog:

Fix feature switch groups (several flag_value options sharing one parameter name) silently dropping an explicit default when a sibling option without an explicit default was declared first. Arbitration is now within ParameterSource.DEFAULT, an option that received an explicit default= keyword wins over a sibling whose default was auto-derived.

Bisected in a scratch mkdocs project to confirm:

click live reload
8.2.1 ON
8.3.0 OFF
8.3.1 OFF
8.3.2 OFF
8.3.3 OFF
8.4.0 ON
8.4.2 ON

So this requires click>=8.4 in the docs group and lets mkdocs-material float from >=9.7.5 (the release that drops the pymdown-extensions~=10.2 cap and adds a mkdocs<2 cap). No --livereload workaround is needed and make docs-serve is unchanged.

Why this matters beyond the docs

Because uv resolves all dependency groups together, the ==9.6.20 pin was holding click at 8.2.1 and pymdown-extensions at 10.x across the entire workspace — including the test and dev environments. marimo's own runtime dependency is click>=8.0,<9, so CI has never exercised the click 8.3/8.4 that users actually get. After this change the workspace resolves click 8.4.2.

It also unblocks CI coverage for #10332 (relaxing the pymdown-extensions cap to allow 11.x) — with the pin in place, that cap could be relaxed but the resolver would still pick 10.x, so CI would never test 11.x. These two PRs are independent and can merge in either order; together they let CI resolve pymdown-extensions 11.x.

Verification

  • mkdocs build --strict passes on both 9.6.20 (baseline) and 9.7.7 — exit 0 each time. The only new console output on 9.7.7 is upstream's informational MkDocs 2.0 banner, which squidfunk notes does not affect strict builds (confirmed).
  • mkdocs serve --clean — the existing docs-serve target verbatim, no extra flags — reports Watching paths for changes: 'docs', 'mkdocs.yml', 'marimo' on click 8.4.2.
  • pytest tests/ -k "not test_cli" (~11k tests) and pytest tests/_cli/test_cli_* show no new failures on click 8.4.2 versus 8.2.1. (Two pre-existing failures on both: test_openapi_up_to_date, and a cluster in tests/_code_mode/ that comes from my own user-level ~/.config/marimo/marimo.toml.)
  • Rendered HTML: 235/236 pages differ, but only as markup normalization (self-closing tags, whitespace), a Font Awesome 7 icon bump, and social meta tags moving from name="twitter:*" to property="twitter:*". All upstream theme changes, no content or structural differences.

One thing worth a maintainer's eye: that name="twitter:*"property="twitter:*" change is upstream's doing, but social card previews on docs.marimo.io are user-visible, so it may be worth a spot check with a card validator after merge.

I could not fully reproduce the CI docs environment locally (my machine needed DYLD_FALLBACK_LIBRARY_PATH=/opt/homebrew/lib for cairosvg to find libcairo for the social plugin), so the strict-build results above come from a locally patched environment rather than the CI image.

📋 Pre-Review Checklist

  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions. — Dev-tooling only; no public API change.
  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • Video or media evidence is provided for any visual changes (optional).

✅ Merge Checklist

  • I have read the contributor guidelines.
  • Documentation has been updated where applicable, including docstrings for API changes — n/a; the reasoning is captured in the pyproject.toml comment that replaces the old one.
  • Tests have been added for the changes made — n/a; this is a dependency-constraint change, covered by the existing mkdocs build --strict docs CI job.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jul 29, 2026 6:09pm

Request Review

@tschm
tschm marked this pull request as ready for review July 25, 2026 19:46
Copilot AI review requested due to automatic review settings July 25, 2026 19:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the documentation dependency set to address MkDocs live-reload behavior by constraining click appropriately, while allowing mkdocs-material to float again (instead of being pinned), so the workspace can resolve newer docs-stack dependencies.

Changes:

  • Replace the mkdocs-material==9.6.20 pin with a floating mkdocs-material>=9.7.5.
  • Add a click>=8.4 requirement in the docs dependency group to avoid MkDocs live-reload issues seen with click 8.3.x.

Comment thread pyproject.toml
# 8.4.0, so require that here rather than pinning mkdocs-material back to
# 9.6.20 (the last release that capped click<8.2.2, which used to mask it).
# https://github.com/squidfunk/mkdocs-material/issues/8478
"click>=8.4",
Comment thread pyproject.toml
docs = [
"marimo_docs",
"ruff>=0.15.18",
"mkdocs>=1.6.1",
mscolnick
mscolnick previously approved these changes Jul 27, 2026
@mscolnick mscolnick added dependencies internal A refactor or improvement that is not user facing labels Jul 27, 2026
mscolnick pushed a commit that referenced this pull request Jul 27, 2026
**This pull request was authored by a coding agent.**

## 📝 Summary

Closes #10328

`pymdown-extensions` was capped at `<11`. That cap has been there since
the initial commit as a conventional major-version guard — the git
history shows every subsequent change only ever moved the *lower* bound.
With `pymdown-extensions` 11.x released, the cap blocks downstream
projects from upgrading while keeping marimo installed:

```
Because marimo depends on pymdown-extensions>=10.21.2,<11 and
pymdown-extensions==11.0.0, we can conclude that marimo cannot be used.
```

This relaxes it to `>=10.21.2,<12`, matching how the rest of the
markdown stack is capped (`markdown<4`, `pygments<3`).

It also replaces the stale `# Pinned to specific version for
introduction of codeblock handling.` comment with the actual reasons for
the lower bound — that comment predates the two bumps that set the
current floor and no longer described it.

### Compatibility with 11.x

Checked each of 11.0's changes against how marimo uses `pymdownx`:

| 11.0 change | Impact on marimo |
| --- | --- |
| Dropped Python 3.9 | None — marimo is already `requires-python =
">=3.10"`, and `pymdown-extensions` 11.x declares `>=3.10` |
| **Breaking:** `pymdownx.b64` restricts relative links to `base_path`
by default (new `restrict_path` option) | None in practice. marimo
enables `b64` **only** under WASM (`marimo/_output/md.py`), scoped to
the notebook directory. Restricting to `base_path` matches the existing
intent — the code comment there already says b64 stays off elsewhere
because "app users could potentially use it to grab files they shouldn't
have access to." The new default is strictly tighter, so no
`restrict_path` override is set (which also keeps 10.x working, since
the option doesn't exist there). |
| `pymdownx.tabbed` empty-title fix | Not used by marimo |
| 11.0.1 regex fixes in BetterEm/Tilde/Caret/MagicLink | No API change |

Every `pymdownx` symbol marimo imports still exists and behaves the same
on 11.0.1: `superfences.RE_NESTED_FENCE_START` and the other superfences
internals (`marimo/_convert/markdown/to_ir.py`,
`marimo/_convert/ipynb/to_ir.py`), `pymdownx.emoji.to_alt`, and the
`pymdownx.blocks` / `pymdownx.blocks.block` API that the docs
`marimo-embed` extension is built on (`docs/blocks/__init__.py`).

### Verification

Ran the CI test selection (`pytest tests/ -k "not test_cli"`, ~11k
tests) twice on `pymdown-extensions==11.0.1` and once on `10.21.3`.
**The results are identical** — same pass count, same failure set. The
failures present in all three runs are pre-existing and local to my
machine (they come from a `manager = "pixi"` setting in my user-level
`~/.config/marimo/marimo.toml` leaking into `tests/_code_mode/`;
unrelated to markdown).

The `pymdownx.b64` WASM round-trip is covered by the existing
`test_md_with_b64_in_wasm`, which actually inlines a PNG and passes on
11.0.1. I also rendered a `marimo-embed` block through the docs
extension on 11.0.1 to confirm the docs blocks API still works.

### One thing for maintainers to note

CI won't actually exercise 11.x yet. The `docs` group pins
`mkdocs-material==9.6.20`, which requires `pymdown-extensions~=10.2`;
because uv resolves all groups together, the whole-workspace resolution
stays on 10.x regardless of this cap. So the 11.x verification above was
done by force-installing `pymdown-extensions==11.0.1` into the test
environment.

#10333 lifts that pin, which lets CI resolve 11.x. The two PRs are
independent and can merge in either order — this one relaxes the cap,
that one lets the resolver act on it.

## 📋 Pre-Review Checklist

- [x] For large changes, or changes that affect the public API: this
change was discussed or approved through an issue, on
[Discord](https://marimo.io/discord?ref=pr), or the community
[discussions](https://github.com/marimo-team/marimo/discussions) —
discussed in #10328.
- [x] Any AI generated code has been reviewed line-by-line by the human
PR author, who stands by it.
- [ ] Video or media evidence is provided for any visual changes
(optional).

## ✅ Merge Checklist

- [x] I have read the [contributor
guidelines](https://github.com/marimo-team/marimo/blob/main/CONTRIBUTING.md).
- [x] Documentation has been updated where applicable, including
docstrings for API changes — n/a, no user-facing API change.
- [x] Tests have been added for the changes made — the
`tests/snapshots/dependencies.txt` snapshot asserted by
`tests/test_project_dependencies.py` is updated to the new constraint;
no new behavior to test.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
tschm and others added 2 commits July 29, 2026 21:35
`mkdocs-material` was pinned to `==9.6.20` because live reload broke in
`>= 9.6.21`. The pin treats a symptom: 9.6.20 is simply the last release
that capped `click<8.2.2`, and it was that incidental click cap doing the
work.

The actual bug is in click. MkDocs declares `--no-livereload` /
`--livereload` as a feature switch group — two `flag_value` options
sharing one parameter name — where only the second carries
`default=True`. click 8.3.0 started dropping that explicit default when a
sibling without one was declared first, so `mkdocs serve` silently came
up with live reload off. click 8.4.0 fixed it ("an option that received
an explicit `default=` keyword wins over a sibling whose default was
auto-derived").

Bisected in a scratch mkdocs project:

    click 8.2.1  live reload ON
    click 8.3.0  OFF
    click 8.3.1  OFF
    click 8.3.2  OFF
    click 8.3.3  OFF
    click 8.4.0  ON
    click 8.4.2  ON

So require `click>=8.4` in the docs group and let mkdocs-material float
from 9.7.5 (the release that drops the `pymdown-extensions~=10.2` cap and
caps `mkdocs<2`). No `--livereload` workaround is needed, and
`make docs-serve` is unchanged.

This matters beyond the docs. Because uv resolves all groups together,
the `==9.6.20` pin was holding `click` at 8.2.1 and `pymdown-extensions`
at 10.x across the *whole* workspace — so the test and dev environments
never saw the click 8.3/8.4 that marimo's own `click>=8.0,<9` allows
users to install. After this change the workspace resolves click 8.4.2.

Verified:

- `mkdocs build --strict` passes on both 9.6.20 and 9.7.7. The only new
  console output is upstream's informational MkDocs 2.0 banner, which
  does not affect strict mode.
- `mkdocs serve --clean` (the existing docs-serve target, no extra flags)
  reports "Watching paths for changes" on click 8.4.2.
- `tests/` (minus `test_cli`) and `tests/_cli/test_cli_*` show no new
  failures on click 8.4.2 versus 8.2.1.
- Rendered HTML differs on 235/236 pages, but only as markup
  normalization (self-closing tags, whitespace), a Font Awesome 7 icon
  bump, and social meta tags moving from `name="twitter:*"` to
  `property="twitter:*"` — all upstream theme changes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
click 8.4 declares `NoSuchOption.possibilities` as `Final`, so assigning to
it fails typechecking:

    marimo/_cli/help_formatter.py:58: error: Cannot assign to final
    attribute "possibilities"  [misc]

Click only ever fills in `possibilities` for long options, and marimo reads
the attribute in exactly one place, so compute short-flag suggestions where
they are rendered instead of writing them back onto click's exception. This
also drops the two `parse_args` overrides that existed only to perform that
mutation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@tschm
tschm force-pushed the bump-mkdocs-material branch from 94df017 to ea3d519 Compare July 29, 2026 18:06
@mscolnick
mscolnick merged commit b519d4b into marimo-team:main Jul 29, 2026
47 checks passed
@github-actions

Copy link
Copy Markdown
Contributor


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


1 out of 2 committers have signed the CLA.
tschm
@claude Opus 5 (1M context)

Warning

1 commit in this PR was authored by an email address that is not linked to any GitHub user, so we cannot tell whether the author has signed the CLA.

Unlinked author:

  • Claude Opus 5 (1M context) <noreply@anthropic.com>

To unblock this PR, do one of the following:

  1. Link the email to your GitHub account (recommended). Add each address above at github.com/settings/emails, then push another commit (or comment recheck) so this check re-runs. See why commits are not linked to a user for details.

  2. Rewrite the commits to use an email that is already linked to your GitHub account:

    # Set the correct email locally (one-off, for this repo):
    git config user.email you@example.com
    # Rewrite every commit on this branch with the corrected identity:
    git rebase -i --root --exec 'git commit --amend --reset-author --no-edit'
    git push --force-with-lease

    After the push, comment recheck on this PR (or just re-push) to re-run the check.

    You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.16-dev40

tschm added a commit to tschm/marimo that referenced this pull request Jul 30, 2026
Our floor of 10.21.2 sits below three published advisories, so scanners
flag every downstream lockfile that resolves it:

- CVE-2026-46338 (GHSA-62q4-447f-wv8h): sibling-prefix path traversal in
  `pymdownx.snippets` despite `restrict_base_path`; fixed in 10.21.3.
- CVE-2026-61632 (GHSA-9xwg-3r6f-jcx2): path traversal in `pymdownx.b64`
  lets `<img src>` read outside `base_path`; fixed in 11.0.0. We enable
  b64 under WASM with `base_path` set to the notebook directory.
- CVE-2026-67422 (GHSA-gm37-52c6-37mw, CVSS 7.5): exponential-backtracking
  ReDoS in the caret, tilde, betterem and magiclink inline processors;
  fixed in 11.0.1. We enable caret, tilde and magiclink by default, so a
  sub-50-byte line of untrusted markdown passed to `mo.md` can pin a CPU.

Relaxing the upper bound (marimo-team#10332) made 11.x installable; only a floor
bump makes it certain. 11.0.1 requires Python >=3.10, which matches our
`requires-python`, and mkdocs-material>=9.7.5 (marimo-team#10333) no longer caps
pymdown-extensions, so the docs group resolves too.

Closes marimo-team#10392
tschm added a commit to tschm/marimo that referenced this pull request Jul 30, 2026
Our floor of 10.21.2 sits below three published advisories, so scanners
flag every downstream lockfile that resolves it:

- CVE-2026-46338 (GHSA-62q4-447f-wv8h): sibling-prefix path traversal in
  `pymdownx.snippets` despite `restrict_base_path`; fixed in 10.21.3.
- CVE-2026-61632 (GHSA-9xwg-3r6f-jcx2): path traversal in `pymdownx.b64`
  lets `<img src>` read outside `base_path`; fixed in 11.0.0. We enable
  b64 under WASM with `base_path` set to the notebook directory.
- CVE-2026-67422 (GHSA-gm37-52c6-37mw, CVSS 7.5): exponential-backtracking
  ReDoS in the caret, tilde, betterem and magiclink inline processors;
  fixed in 11.0.1. We enable caret, tilde and magiclink by default, so a
  sub-50-byte line of untrusted markdown passed to `mo.md` can pin a CPU.

Relaxing the upper bound (marimo-team#10332) made 11.x installable; only a floor
bump makes it certain. 11.0.1 requires Python >=3.10, which matches our
`requires-python`, and mkdocs-material>=9.7.5 (marimo-team#10333) no longer caps
pymdown-extensions, so the docs group resolves too.

Closes marimo-team#10392

Co-authored-by: Shahmir Varqha <Sham9871@gmail.com>
tschm added a commit to tschm/marimo that referenced this pull request Jul 30, 2026
Our floor of 10.21.2 sits below three published advisories, so scanners
flag every downstream lockfile that resolves it:

- CVE-2026-46338 (GHSA-62q4-447f-wv8h): sibling-prefix path traversal in
  `pymdownx.snippets` despite `restrict_base_path`; fixed in 10.21.3.
- CVE-2026-61632 (GHSA-9xwg-3r6f-jcx2): path traversal in `pymdownx.b64`
  lets `<img src>` read outside `base_path`; fixed in 11.0.0. We enable
  b64 under WASM with `base_path` set to the notebook directory.
- CVE-2026-67422 (GHSA-gm37-52c6-37mw, CVSS 7.5): exponential-backtracking
  ReDoS in the caret, tilde, betterem and magiclink inline processors;
  fixed in 11.0.1. We enable caret, tilde and magiclink by default, so a
  sub-50-byte line of untrusted markdown passed to `mo.md` can pin a CPU.

Relaxing the upper bound (marimo-team#10332) made 11.x installable; only a floor
bump makes it certain. 11.0.1 requires Python >=3.10, which matches our
`requires-python`, and mkdocs-material>=9.7.5 (marimo-team#10333) no longer caps
pymdown-extensions, so the docs group resolves too.

Closes marimo-team#10392

The comment wording (caret/tilde/magiclink, not betterem, are the
extensions we enable) is Light2Dark's correction from their review of
this PR. Credited here rather than as a Co-authored-by trailer because
CLA Assistant treats trailer identities as unsigned committers and
cannot resolve them to a GitHub account.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies internal A refactor or improvement that is not user facing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mkdocs-material==9.6.20 pin holds click and pymdown-extensions back workspace-wide

3 participants