diff --git a/.github/workflows/reusable-cookie.yml b/.github/workflows/reusable-cookie.yml index c0361cae..618abebd 100644 --- a/.github/workflows/reusable-cookie.yml +++ b/.github/workflows/reusable-cookie.yml @@ -58,8 +58,8 @@ jobs: - name: Test poetry run: nox -s 'tests(poetry, novcs)' -s 'tests(poetry, vcs, sphinx)' - - name: Test flit (mkdocs) - run: nox -s 'tests(flit, novcs)' -s 'tests(flit, vcs, mkdocs)' + - name: Test flit (properdocs) + run: nox -s 'tests(flit, novcs)' -s 'tests(flit, vcs, properdocs)' - name: Test uv (zensical) run: nox -s 'tests(uv, novcs, zensical)' @@ -131,7 +131,7 @@ jobs: - name: Test scikit-build run: | nox -s 'nox(skbuild, vcs, sphinx)' - nox -s 'nox(skbuild, vcs, mkdocs)' -- docs + nox -s 'nox(skbuild, vcs, properdocs)' -- docs - name: Test poetry run: | @@ -141,7 +141,7 @@ jobs: - name: Test flit run: | nox -s 'nox(flit, novcs, zensical)' - nox -s 'nox(flit, novcs, mkdocs)' -- docs + nox -s 'nox(flit, novcs, properdocs)' -- docs - name: Test pdm run: | @@ -155,8 +155,8 @@ jobs: - name: Test hatch run: | - nox -s 'nox(hatch, vcs, mkdocs)' - nox -s 'nox(hatch, vcs, mkdocs)' -- docs + nox -s 'nox(hatch, vcs, properdocs)' + nox -s 'nox(hatch, vcs, properdocs)' -- docs - name: Test setuptools PEP 621 run: | diff --git a/.gitignore b/.gitignore index ff0efca2..ab2045dd 100644 --- a/.gitignore +++ b/.gitignore @@ -119,7 +119,7 @@ venv.bak/ # Rope project settings .ropeproject -# mkdocs documentation +# mkdocs/properdocs documentation /site # mypy diff --git a/AGENTS.md b/AGENTS.md index 86ffdaac..c9bc9bd3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,7 +23,7 @@ Important: tests run with `PYTHONWARNDEFAULTENCODING=1`. ### Cookie template validation The noxfile generates temporary projects for **all 9 backends** × **vcs on/off** -× **3 docs engines** (sphinx/mkdocs/zensical). These are slow. +× **3 docs engines** (sphinx/properdocs/zensical). These are slow. - `nox -s "tests(hatch)"` — run generated project tests for a single backend - `nox -s "lint(hatch)"` — run pre-commit (`prek`) on generated project @@ -86,7 +86,7 @@ The noxfile generates temporary projects for **all 9 backends** × **vcs on/off* - The repo-review interactive page is embedded using an `{anywidget}` directive (see `docs/pages/guides/repo_review.md`). - Tab-sets use `:sync: ` for cross-page tab synchronization, where the - sync key is the tab label itself (e.g., `sphinx`, `mkdocs`, + sync key is the tab label itself (e.g., `sphinx`, `properdocs`, `trusted-publishing`, `scikit-build-core`). - TOML code blocks in the docs use "ini" to get syntax highlighting for now. This is applied only at the docs layer (the `code_fence` cog helper in diff --git a/README.md b/README.md index aabd8488..b61447fb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ templates for Python packages? clearly documented and every tool described, and everything is kept in sync. - Ten different backends to choose from for building packages. - Optional VCS versioning for most backends. -- Selection for your preferred documentation engine (Sphinx, MkDocs, or +- Selection for your preferred documentation engine (Sphinx, ProperDocs, or Zensical). - Template generation tested in GitHub Actions using nox. - Supports generation with [copier][], [cookiecutter][], and [cruft][]. diff --git a/cookiecutter.json b/cookiecutter.json index 9a583977..713cbc2d 100644 --- a/cookiecutter.json +++ b/cookiecutter.json @@ -18,7 +18,7 @@ "mesonpy", "maturin" ], - "docs": ["sphinx", "mkdocs", "zensical"], + "docs": ["sphinx", "properdocs", "zensical"], "vcs": true, "__year": "{% now 'utc', '%Y' %}", "__project_slug": "{{ cookiecutter.project_name | lower | replace('-', '_') | replace('.', '_') }}", @@ -49,7 +49,7 @@ "docs": { "__prompt__": "Choose your documentation tool", "sphinx": "Sphinx", - "mkdocs": "MkDocs", + "properdocs": "ProperDocs (MkDocs fork)", "zensical": "Zensical (alpha)" }, "vcs": "Use version control for versioning" diff --git a/copier.yml b/copier.yml index f4c3d96f..092afcbd 100644 --- a/copier.yml +++ b/copier.yml @@ -87,7 +87,7 @@ docs: help: Choose your documentation tool choices: "Sphinx": sphinx - "MkDocs": mkdocs + "ProperDocs (MkDocs fork)": properdocs "Zensical (alpha)": zensical # [[[end]]] diff --git a/docs/guides/docs.md b/docs/guides/docs.md index 73d89f12..303712ad 100644 --- a/docs/guides/docs.md +++ b/docs/guides/docs.md @@ -3,7 +3,8 @@ Documentation used to require learning reStructuredText (sometimes referred to as reST / rST), but today we have great choices for documentation in markdown, the same format used by GitHub, Wikipedia, and others. This guide covers Sphinx -(using the modern MyST plugin to get Markdown support), MkDocs, and Zensical. +(using the modern MyST plugin to get Markdown support), ProperDocs, and +Zensical. :::{note} Popular frameworks The three frameworks covered in this guide are the ones supported by the cookie @@ -15,8 +16,8 @@ template. There are lots of options, though: [astropy](https://docs.astropy.org/en/stable/index_user_docs.html) and [corner](https://corner.readthedocs.io). The MyST parser enables markdown support. -- [MkDocs](https://www.mkdocs.org) / - [ProperDocs](https://github.com/ProperDocs/properdocs): A from-scratch +- [ProperDocs](https://properdocs.org), a maintained fork of + [MkDocs](https://www.mkdocs.org): A from-scratch documentation system based on markdown and HTML. Less support for man pages & PDFs than Sphinx, since it doesn't use docutils. Has over [200 plugins](https://github.com/mkdocs/catalog) - they are much easier to write @@ -44,10 +45,11 @@ template. There are lots of options, though: With the creators of `mkdocs-material` and `mkdocstrings` now working on [Zensical](https://zensical.org/about/), MkDocs's future is uncertain, and mkdocs-material will be minimally maintained until late 2026. -[ProperDocs](https://github.com/ProperDocs/properdocs) is a fork of MkDocs -keeping compatibility with old plugins. MkDocs is threatening a complete -reworking without plugins support for its next release, and then all public -activity has ceased. [Read more](https://fpgmaas.com/blog/collapse-of-mkdocs/). +[ProperDocs](https://properdocs.org), started by a former MkDocs maintainer, +is a drop-in fork of MkDocs keeping compatibility with existing plugins; the +cookie uses it. MkDocs was threatening a complete reworking without plugin +support for its next release, and then all public activity ceased. +[Read more](https://fpgmaas.com/blog/collapse-of-mkdocs/). ::: ## What to include @@ -74,10 +76,10 @@ with render_cookie(backend="hatch", docs="sphinx") as package: docs_index_md = package.joinpath("docs/index.md").read_text(encoding="utf-8").strip() readthedocs_yaml = package.joinpath(".readthedocs.yaml").read_text(encoding="utf-8").strip() noxfile = PyMatcher.from_file(package / "noxfile.py") -with render_cookie(backend="hatch", docs="mkdocs") as package: - mkdocs_conf_yaml = package.joinpath("mkdocs.yml").read_text(encoding="utf-8").strip() - noxfile_mkdocs = PyMatcher.from_file(package / "noxfile.py") - readthedocs_yaml_mkdocs = package.joinpath(".readthedocs.yaml").read_text(encoding="utf-8").strip() +with render_cookie(backend="hatch", docs="properdocs") as package: + properdocs_conf_yaml = package.joinpath("properdocs.yml").read_text(encoding="utf-8").strip() + noxfile_properdocs = PyMatcher.from_file(package / "noxfile.py") + readthedocs_yaml_properdocs = package.joinpath(".readthedocs.yaml").read_text(encoding="utf-8").strip() with render_cookie(backend="hatch", docs="zensical") as package: zensical_conf_toml = package.joinpath("zensical.toml").read_text(encoding="utf-8").strip() noxfile_zensical = PyMatcher.from_file(package / "noxfile.py") @@ -277,14 +279,17 @@ to mark where you want the docs portion to start. You can add the standard indices and tables at the end. ::: -:::{tab-item} MkDocs -:sync: mkdocs -While the cookie cutter creates a basic structure for your MkDocs (a top level -`mkdocs.yml` file and the `docs` directory), you can also follow the official -[Getting started](https://squidfunk.github.io/mkdocs-material/getting-started/) +:::{tab-item} ProperDocs +:sync: properdocs +ProperDocs is a maintained, drop-in-compatible fork of MkDocs, so almost all +MkDocs documentation and plugins apply to it as well. While the cookie cutter +creates a basic structure for your ProperDocs site (a top level +`properdocs.yml` file and the `docs` directory), you can also follow the +official +[Getting started](https://properdocs.org/getting-started) guide instead. -If you selected the `mkdocs` option when using the template cookie-cutter +If you selected the `properdocs` option when using the template cookie-cutter repository, you will already have this group. Otherwise, add to your `pyproject.toml`: @@ -294,8 +299,8 @@ docs = [ "markdown>=3.9", "mdx-include>=1.4.2", "mkdocs-material>=9.1.19", - "mkdocs>=1.1.2,", "mkdocstrings-python>=1.18.2", + "properdocs>=1.6.7", "pyyaml>=6.0.1", ] ``` @@ -306,11 +311,11 @@ install, or install all groups, such as by running `uv sync --all-groups`. These dependencies include several common plugins---such as generating reference API documentation from docstrings---to make life easier. -Similar to Sphinx, MkDocs puts your written documentation into the `/docs` -directory, but also has a top-level `mkdocs.yml` configuration file. You can see -the +Similar to Sphinx, ProperDocs puts your written documentation into the `/docs` +directory, but also has a top-level `properdocs.yml` configuration file +(ProperDocs also reads the legacy `mkdocs.yml` name). You can see the [minimal configuration for the file here](https://squidfunk.github.io/mkdocs-material/creating-your-site/#minimal-configuration), -which is only four lines. However, the `mkdocs.yml` file bundled with the +which is only four lines. However, the `properdocs.yml` file bundled with the template repository have many options pre-configured. Let's run through an example configuration now. @@ -318,7 +323,7 @@ Here's the whole file for completeness. We'll break it into sections underneath. ```yaml @@ -438,7 +443,8 @@ theme: name: Switch to dark mode ``` -Onto the best part of MkDocs: it's many plugins! +Onto the best part of the MkDocs ecosystem: its many plugins, which ProperDocs +keeps working! - `search` enabled search functionality. - [`autorefs`](https://mkdocstrings.github.io/autorefs/) allows easier linking @@ -492,8 +498,8 @@ docs = [ You should include the docs group via `--group=docs` when using uv or pip to install, or install all groups, such as by running `uv sync --all-groups`. -Like MkDocs, Zensical reads your written documentation from the `docs` -directory, with a top-level config file, `zensical.toml`. Unlike MkDocs, it +Like ProperDocs, Zensical reads your written documentation from the `docs` +directory, with a top-level config file, `zensical.toml`. Unlike ProperDocs, it doesn't require a `nav`; if you don't give one, it builds the navigation from your file layout. The theme is a built-in evolution of `mkdocs-material`, so the [feature flags](https://zensical.org/docs/setup/) and palette options will @@ -613,11 +619,11 @@ python: ::: -:::{tab-item} MkDocs -:sync: mkdocs +:::{tab-item} ProperDocs +:sync: properdocs ```yaml @@ -636,7 +642,7 @@ build: - asdf install uv latest - asdf global uv latest - uv sync --group docs - - uv run mkdocs build --site-dir $READTHEDOCS_OUTPUT/html + - uv run properdocs build --site-dir $READTHEDOCS_OUTPUT/html ``` @@ -742,11 +748,11 @@ the autobuild (when interactive) or a regular build. We could have just added `python -m http.server` pointing at the built documentation, but autobuild will rebuild if you change a file while serving. ::: -:::{tab-item} MkDocs -:sync: mkdocs +:::{tab-item} ProperDocs +:sync: properdocs ```python @@ -760,19 +766,20 @@ def docs(session: nox.Session) -> None: session.install("-e.", *doc_deps) if session.interactive: - session.run("mkdocs", "serve", "--clean", *session.posargs) + session.run("properdocs", "serve", "--clean", *session.posargs) else: - session.run("mkdocs", "build", "--clean", *session.posargs) + session.run("properdocs", "build", "--clean", *session.posargs) ``` -This Nox job will invoke MkDocs to serve a live copy of your documentation under -a local endpoint, such as `http://localhost:8080` (the link will be in the job -output). By requesting a `serve` instead of a `build`, any time documentation or -the source code is changed, the documentation will automatically update. For -documentation on how to configure what directories are watched for changes, -[consult the MkDocs configuration page](https://www.mkdocs.org/user-guide/configuration/#live-reloading). +This Nox job will invoke ProperDocs to serve a live copy of your documentation +under a local endpoint, such as `http://localhost:8080` (the link will be in +the job output). By requesting a `serve` instead of a `build`, any time +documentation or the source code is changed, the documentation will +automatically update. For documentation on how to configure what directories +are watched for changes, +[consult the ProperDocs configuration page](https://properdocs.org/user-guide/configuration/#live-reloading). ::: :::{tab-item} Zensical :sync: zensical @@ -799,7 +806,8 @@ def docs(session: nox.Session) -> None: -This is nearly identical to the MkDocs job: `zensical serve` gives you a live +This is nearly identical to the ProperDocs job: `zensical serve` gives you a +live preview that rebuilds when files change (and it's fast — rebuilds are incremental), while `zensical build` produces the static site in `site/`. ::: @@ -857,11 +865,11 @@ api/ Note that your docstrings are still parsed as reStructuredText. ::: -:::{tab-item} MkDocs -:sync: mkdocs +:::{tab-item} ProperDocs +:sync: properdocs API documentation can be built from your docstring using the `mkdocstrings` plugin, as referenced previously. Unlike with Sphinx, which requires a direct -invocation of `sphinx-apidoc`, MkDocs plugins are integrated into the MkDocs +invocation of `sphinx-apidoc`, plugins are integrated into the ProperDocs build. All `mkdocstrings` requires is your markdown files to specify what module, @@ -885,7 +893,7 @@ module by being more specific, like `::: my_package.my_module.MyClass`. :::{tab-item} Zensical :sync: zensical Zensical has preliminary support for `mkdocstrings`, using the same triple -colon syntax as MkDocs (see the MkDocs tab). Add `mkdocstrings-python` to your +colon syntax (see the ProperDocs tab). Add `mkdocstrings-python` to your `docs` dependency group, then configure the handler in `zensical.toml`: ```toml @@ -932,8 +940,8 @@ for this to work. CI services like readthedocs usually have it installed. If you want to use Markdown instead of notebooks, you can use jupytext (see [here](https://nbsphinx.readthedocs.io/en/0.9.2/a-markdown-file.html)). ::: -:::{tab-item} MkDocs -:sync: mkdocs +:::{tab-item} ProperDocs +:sync: properdocs You can combine notebooks into your docs. The plugin for this is `mkdocs-jupyter`, and configuration is detailed [here](https://github.com/danielfrg/mkdocs-jupyter) and you can find examples @@ -941,7 +949,7 @@ You can combine notebooks into your docs. The plugin for this is Once you have a notebook (which has been run and populated with results, as the plugin will not execute your notebooks for you), you simply need to add a link -to the notebook in your `mkdocs.yml` navigation. +to the notebook in your `properdocs.yml` navigation. ```yaml nav: @@ -963,8 +971,8 @@ show `mkdocs-gallery` in action. :sync: zensical Zensical does not support MkDocs plugins like `mkdocs-jupyter`, and it has no notebook support of its own yet. If notebooks are central to your docs, use -Sphinx or MkDocs for now, or pre-convert notebooks to Markdown with jupytext -as part of your build. +Sphinx or ProperDocs for now, or pre-convert notebooks to Markdown with +jupytext as part of your build. ::: :::: diff --git a/docs/tutorials/docs.md b/docs/tutorials/docs.md index e519e5d0..3a3879b2 100644 --- a/docs/tutorials/docs.md +++ b/docs/tutorials/docs.md @@ -26,10 +26,11 @@ to be displayed to the user. There are a variety of tools that can do this. In this guide we will present two approaches that are mainstream in the scientific Python community: the -[Sphinx][] documentation generator with the [MyST][] plugin, and the [MkDocs][] -generator via [mkdocs-material][]. +[Sphinx][] documentation generator with the [MyST][] plugin, and the +[ProperDocs][] generator (a maintained fork of [MkDocs][]) via +[mkdocs-material][]. -For more details, examples to help you pick between Sphinx and MkDocs (and +For more details, examples to help you pick between Sphinx and ProperDocs (and instructions for the latter), see the [documentation guide][]. For this simple introduction, we will use Sphinx as it is still more popular with scientific libraries. @@ -203,5 +204,6 @@ integrate this into a package, and setup for nox. [organizing content]: https://myst-parser.readthedocs.io/en/latest/syntax/organising_content.html [sphinx-autodoc2]: https://sphinx-autodoc2.readthedocs.io/ [mkdocs]: https://www.mkdocs.org/ +[properdocs]: https://properdocs.org/ [mkdocs-material]: https://squidfunk.github.io/mkdocs-material/ [documentation guide]: /guides/docs.md diff --git a/noxfile.py b/noxfile.py index 34e4f958..744d9c23 100755 --- a/noxfile.py +++ b/noxfile.py @@ -41,7 +41,7 @@ class Docs(enum.Enum): Sphinx = "sphinx" - MkDocs = "mkdocs" + ProperDocs = "properdocs" Zensical = "zensical" diff --git a/{{cookiecutter.project_name}}/.gitignore b/{{cookiecutter.project_name}}/.gitignore index a0eee367..1b8369e1 100644 --- a/{{cookiecutter.project_name}}/.gitignore +++ b/{{cookiecutter.project_name}}/.gitignore @@ -142,7 +142,7 @@ venv.bak/ # Rope project settings .ropeproject -# mkdocs documentation +# mkdocs/properdocs documentation /site # mypy diff --git a/{{cookiecutter.project_name}}/.readthedocs.yaml b/{{cookiecutter.project_name}}/.readthedocs.yaml index f3bf0e9e..17d7c8a5 100644 --- a/{{cookiecutter.project_name}}/.readthedocs.yaml +++ b/{{cookiecutter.project_name}}/.readthedocs.yaml @@ -27,8 +27,8 @@ python: - asdf install uv latest - asdf global uv latest - uv sync --group docs - {%- if cookiecutter.docs == 'mkdocs' %} - - uv run mkdocs build --site-dir $READTHEDOCS_OUTPUT/html + {%- if cookiecutter.docs == 'properdocs' %} + - uv run properdocs build --site-dir $READTHEDOCS_OUTPUT/html {%- elif cookiecutter.docs == 'zensical' %} - uv run zensical build - mkdir -p $READTHEDOCS_OUTPUT/html/ diff --git a/{{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'mkdocs' %}api.md{% endif %} b/{{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'properdocs' %}api.md{% endif %} similarity index 100% rename from {{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'mkdocs' %}api.md{% endif %} rename to {{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'properdocs' %}api.md{% endif %} diff --git a/{{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'mkdocs' %}index.md{% endif %} b/{{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'properdocs' %}index.md{% endif %} similarity index 100% rename from {{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'mkdocs' %}index.md{% endif %} rename to {{cookiecutter.project_name}}/docs/{% if cookiecutter.docs == 'properdocs' %}index.md{% endif %} diff --git a/{{cookiecutter.project_name}}/noxfile.py b/{{cookiecutter.project_name}}/noxfile.py index 04f014dc..002f91dc 100755 --- a/{{cookiecutter.project_name}}/noxfile.py +++ b/{{cookiecutter.project_name}}/noxfile.py @@ -108,7 +108,7 @@ def build_api_docs(session: nox.Session) -> None: ) -{%- elif cookiecutter.docs == 'mkdocs' %} +{%- elif cookiecutter.docs == 'properdocs' %} @nox.session(reuse_venv=True, default=False) @@ -121,9 +121,9 @@ def docs(session: nox.Session) -> None: session.install("{% if cookiecutter.backend != "mesonpy" %}-e{% endif %}.", *doc_deps) if session.interactive: - session.run("mkdocs", "serve", "--clean", *session.posargs) + session.run("properdocs", "serve", "--clean", *session.posargs) else: - session.run("mkdocs", "build", "--clean", *session.posargs) + session.run("properdocs", "build", "--clean", *session.posargs) {%- elif cookiecutter.docs == 'zensical' %} diff --git a/{{cookiecutter.project_name}}/pyproject.toml b/{{cookiecutter.project_name}}/pyproject.toml index e5f46889..7be19002 100644 --- a/{{cookiecutter.project_name}}/pyproject.toml +++ b/{{cookiecutter.project_name}}/pyproject.toml @@ -133,13 +133,13 @@ docs = [ "sphinx_autodoc_typehints", "furo>=2023.08.17", ] -{%- elif cookiecutter.docs == "mkdocs" %} +{%- elif cookiecutter.docs == "properdocs" %} docs = [ "markdown>=3.9", "mdx-include>=1.4.2", "mkdocs-material>=9.1.19", - "mkdocs>=1.1.2", "mkdocstrings-python>=1.18.2", + "properdocs>=1.6.7", "pyyaml>=6.0.1", ] {%- elif cookiecutter.docs == "zensical" %} @@ -333,7 +333,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "tests/**" = ["T20"] "noxfile.py" = ["T20"] -{%- if cookiecutter.docs == "mkdocs" %} +{%- if cookiecutter.docs == "properdocs" %} "docs/examples/**" = ["T20"] {%- endif %} diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.docs=='mkdocs' %}mkdocs.yml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.docs=='properdocs' %}properdocs.yml{% endif %} similarity index 100% rename from {{cookiecutter.project_name}}/{% if cookiecutter.docs=='mkdocs' %}mkdocs.yml{% endif %} rename to {{cookiecutter.project_name}}/{% if cookiecutter.docs=='properdocs' %}properdocs.yml{% endif %}