From b09904d88b08fd0548d90a425098784df71c2bfe Mon Sep 17 00:00:00 2001 From: Frazer McLean Date: Sun, 23 Aug 2026 16:12:14 +0200 Subject: [PATCH] Show pending newsfragments in documentation previews sphinxcontrib-towncrier renders the newsfragments that have not been released yet at the top of the changelog, so that documentation previews built from pull requests include their entries. The title is now rendered by a custom towncrier template instead of title_format, so that the draft gets a plain "Unreleased" heading while releases keep their linked heading, unchanged. --- docs/changelog.rst | 4 ++++ docs/conf.py | 7 ++++++ newsfragments/template.rst.jinja | 39 ++++++++++++++++++++++++++++++++ pyproject.toml | 4 +++- uv.lock | 21 +++++++++++++++++ 5 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 newsfragments/template.rst.jinja diff --git a/docs/changelog.rst b/docs/changelog.rst index 87673de..9f8268a 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,10 @@ Change Log ========== +.. towncrier-draft-entries:: + + Unreleased + .. towncrier release notes start `2.0.0 `_ - 2026-08-10 diff --git a/docs/conf.py b/docs/conf.py index 01ecb02..c03993e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,6 +7,7 @@ import re from importlib.metadata import distribution +from pathlib import Path from parver import Version @@ -44,8 +45,14 @@ "sphinx.ext.mathjax", "sphinx.ext.napoleon", "sphinx.ext.viewcode", + "sphinxcontrib.towncrier.ext", ] +# Render pending newsfragments at the top of the changelog, so that previews +# built from pull requests show their entries. +towncrier_draft_include_empty = False +towncrier_draft_working_directory = str(Path(__file__).resolve().parent.parent) + # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. diff --git a/newsfragments/template.rst.jinja b/newsfragments/template.rst.jinja new file mode 100644 index 0000000..f8e0963 --- /dev/null +++ b/newsfragments/template.rst.jinja @@ -0,0 +1,39 @@ +{% if render_title %} +{% if versiondata.version == "Unreleased" %} +Unreleased +{{ top_underline * 10 }} +{% else %} +{% set title = "`" ~ versiondata.version ~ " `_ - " ~ versiondata.date %} +{{ title }} +{{ top_underline * title|length }} +{% endif %} +{% endif %} +{% for section, _ in sections.items() %} +{% set underline = underlines[0] %}{% if section %}{{section}} +{{ underline * section|length }}{% set underline = underlines[1] %} + +{% endif %} + +{% if sections[section] %} +{% for category, val in definitions.items() if category in sections[section]%} +{{ definitions[category]['name'] }} +{{ underline * definitions[category]['name']|length }} + +{% for text, values in sections[section][category].items() %} +- {% if text %}{{ text }}{% if values %} ({{ values|join(', ') }}){% endif %}{% else %}{{ values|join(', ') }}{% endif %} + +{% endfor %} + +{% if sections[section][category]|length == 0 %} +No significant changes. + +{% else %} +{% endif %} + +{% endfor %} +{% else %} +No significant changes. + + +{% endif %} +{% endfor %} diff --git a/pyproject.toml b/pyproject.toml index dacf9d3..1e6b102 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ docs = [ "furo>=2024.8.6", "parver>=0.5", "sphinx>=7.4.7", + "sphinxcontrib-towncrier>=0.5.0a0", ] docstest = [ { include-group = "docs" }, @@ -116,8 +117,9 @@ ignore = ["D001"] [tool.towncrier] directory = "newsfragments" filename = "docs/changelog.rst" +template = "newsfragments/template.rst.jinja" issue_format = "`#{issue} `_" -title_format = "`{version} `_ - {project_date}" +title_format = "" underlines = ["-", "~"] [[tool.towncrier.type]] diff --git a/uv.lock b/uv.lock index 11aa187..73d8a0f 100644 --- a/uv.lock +++ b/uv.lock @@ -1079,6 +1079,7 @@ dev = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinxcontrib-towncrier" }, { name = "towncrier" }, { name = "trio" }, ] @@ -1088,6 +1089,7 @@ docs = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinxcontrib-towncrier" }, ] docstest = [ { name = "doc8" }, @@ -1096,6 +1098,7 @@ docstest = [ { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "sphinxcontrib-towncrier" }, ] nox = [ { name = "nox" }, @@ -1136,6 +1139,7 @@ dev = [ { name = "pytest", specifier = ">=9.0.3" }, { name = "ruff", specifier = "==0.15.16" }, { name = "sphinx", specifier = ">=7.4.7" }, + { name = "sphinxcontrib-towncrier", specifier = ">=0.5.0a0" }, { name = "towncrier", specifier = ">=25.8.0" }, { name = "trio", specifier = ">=0.33.0" }, ] @@ -1143,12 +1147,14 @@ docs = [ { name = "furo", specifier = ">=2024.8.6" }, { name = "parver", specifier = ">=0.5" }, { name = "sphinx", specifier = ">=7.4.7" }, + { name = "sphinxcontrib-towncrier", specifier = ">=0.5.0a0" }, ] docstest = [ { name = "doc8", specifier = ">=1.1.2" }, { name = "furo", specifier = ">=2024.8.6" }, { name = "parver", specifier = ">=0.5" }, { name = "sphinx", specifier = ">=7.4.7" }, + { name = "sphinxcontrib-towncrier", specifier = ">=0.5.0a0" }, ] nox = [{ name = "nox", specifier = ">=2026.4.10" }] test = [ @@ -1319,6 +1325,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072, upload-time = "2024-07-29T01:10:08.203Z" }, ] +[[package]] +name = "sphinxcontrib-towncrier" +version = "0.5.0a0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "sphinx", version = "8.1.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "towncrier" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/fe/72ed57093e28af10595c50839b183c5fdf0952482e9ef0ca6eb90eb85c5d/sphinxcontrib_towncrier-0.5.0a0.tar.gz", hash = "sha256:294e69df6e275e7a86df7ea6a927cc7c28c2c370a884cd5c45de6ec989858f27", size = 62453, upload-time = "2025-02-28T01:59:16.894Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/5c/f7e39f243636a5e1894f2f5a72579977bf3968922afdb75175ee45062066/sphinxcontrib_towncrier-0.5.0a0-py3-none-any.whl", hash = "sha256:11d130c3ad5e4649821d543c4ea7ab64bbe78df4d859ef94f4298e7845dc0f59", size = 12609, upload-time = "2025-02-28T01:59:15.178Z" }, +] + [[package]] name = "stevedore" version = "5.8.0"