Repository navigation
Expand file tree
/
Copy pathnoxfile.py
More file actions
173 lines (140 loc) · 5.9 KB
/
Copy pathnoxfile.py
File metadata and controls
173 lines (140 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
"""nox build configuration for Documenteer."""
import os
import shutil
from pathlib import Path
import nox
from nox_uv import session
# Default sessions (run when nox is invoked without -s) stay lean: lint, the
# Sphinx 8/9 test runs on Python 3.13, Sphinx 8 typing, and a docs build. The
# full Python x Sphinx grid (3.12-3.14, including the Sphinx "dev" runs) is
# opt-in via ``nox -s test`` / ``nox -s typing``.
nox.options.sessions = [
"lint",
"typing-3.13(sphinx='8')",
"test-3.13(sphinx='8')",
"test-3.13(sphinx='9')",
"docs",
]
# Other nox defaults
nox.options.default_venv_backend = "uv"
nox.options.reuse_existing_virtualenvs = True
# Extras carrying the Sphinx themes and extensions for guides and technotes.
# These cover everything needed to test, type-check, and build the docs.
_EXTRAS = ["guide", "technote"]
# The three demo technote projects built by the ``demo`` session.
_DEMOS = ["rst-technote", "md-technote", "ipynb-technote"]
# Map each Sphinx parametrize ID to the pip requirement that overrides the
# Sphinx version resolved from uv.lock in the session environment.
_SPHINX_SPECS = {
"8": "sphinx==8.*",
"9": "sphinx==9.*",
"dev": "git+https://github.com/sphinx-doc/sphinx.git#egg=sphinx",
}
def _override_sphinx(session: nox.Session, sphinx: str) -> None:
"""Install a specific Sphinx version over the resolved environment.
nox_uv installs the project with the locked Sphinx; this then pins the
parametrized Sphinx version on top via ``uv pip install``, reproducing the
per-factor ``deps`` of the old tox test/typing environments.
"""
session.install(_SPHINX_SPECS[sphinx])
@session(uv_only_groups=["lint"], uv_no_install_project=True)
def lint(session: nox.Session) -> None:
"""Run the prek hooks (incl. the prettier web-asset hook)."""
session.run("prek", "run", "--all-files", *session.posargs)
@session(
python=["3.12", "3.13", "3.14"], uv_groups=["test"], uv_extras=_EXTRAS
)
@nox.parametrize("sphinx", ["8", "9", "dev"])
def test(session: nox.Session, sphinx: str) -> None:
"""Run the test suite with pytest.
Coverage is opt-in: set the ``DOCUMENTEER_COVERAGE`` environment variable
to run under coverage and emit a combined report after the test sessions.
In CI, where each matrix cell uploads its raw ``.coverage.*`` for a central
combine job, also set ``DOCUMENTEER_COVERAGE_NO_COMBINE`` to skip the
per-invocation combine and preserve the un-combined data files.
"""
_override_sphinx(session, sphinx)
if os.environ.get("DOCUMENTEER_COVERAGE"):
session.run("coverage", "run", "-m", "pytest", *session.posargs)
if not os.environ.get("DOCUMENTEER_COVERAGE_NO_COMBINE"):
session.notify("coverage-report")
else:
session.run("pytest", *session.posargs)
@session(
python=["3.12", "3.13", "3.14"], uv_groups=["typing"], uv_extras=_EXTRAS
)
@nox.parametrize("sphinx", ["8", "9", "dev"])
def typing(session: nox.Session, sphinx: str) -> None:
"""Check type annotations with mypy."""
_override_sphinx(session, sphinx)
session.run("mypy", "src", "tests", *session.posargs)
@session(
name="coverage-report", uv_only_groups=["test"], uv_no_install_project=True
)
def coverage_report(session: nox.Session) -> None:
"""Combine and report coverage from the test sessions.
Triggered automatically after the ``test`` sessions when
``DOCUMENTEER_COVERAGE`` is set; may also be run directly to re-display the
most recent combined report.
"""
if list(Path.cwd().glob(".coverage.*")):
session.run("coverage", "combine")
session.run("coverage", "report")
@session(uv_groups=["docs"], uv_extras=_EXTRAS)
def docs(session: nox.Session) -> None:
"""Build the Sphinx documentation."""
if Path("docs/_build").exists():
shutil.rmtree("docs/_build")
if Path("docs/dev/api/contents").exists():
shutil.rmtree("docs/dev/api/contents")
session.run("make", "-C", "docs", "html", external=True)
@session(name="docs-linkcheck", uv_groups=["docs"], uv_extras=_EXTRAS)
def docs_linkcheck(session: nox.Session) -> None:
"""Check links in the Sphinx documentation."""
session.run("make", "-C", "docs", "linkcheck", external=True)
@session(
python=["3.12", "3.13", "3.14"], uv_groups=["test"], uv_extras=_EXTRAS
)
@nox.parametrize("sphinx", ["8", "9", "dev"])
def demo(session: nox.Session, sphinx: str) -> None:
"""Build the demo technote projects as an end-to-end smoke test.
Parametrized over Python and Sphinx like ``test``/``typing`` so the demo
build is exercised across the full matrix in CI.
"""
_override_sphinx(session, sphinx)
for demo_name in _DEMOS:
build_dir = Path("demo") / demo_name / "_build"
if build_dir.exists():
shutil.rmtree(build_dir)
doctree_dir = (session.cache_dir / "doctrees" / demo_name).absolute()
session.run(
"sphinx-build",
"--keep-going",
"-n",
"-W",
"-T",
"-b",
"html",
"-d",
str(doctree_dir),
f"demo/{demo_name}",
f"demo/{demo_name}/_build/html",
)
@nox.session(name="packaging")
def packaging(session: nox.Session) -> None:
"""Check the PyPI package build with twine."""
if Path("dist").exists():
shutil.rmtree("dist")
session.install("build", "twine")
session.run("python", "-m", "build")
session.run("twine", "check", *[str(p) for p in Path("dist").glob("*")])
@nox.session(name="scriv-create")
def scriv_create(session: nox.Session) -> None:
"""Create a changelog fragment."""
session.install("scriv")
session.run("scriv", "create")
@nox.session(name="scriv-collect")
def scriv_collect(session: nox.Session) -> None:
"""Collect changelog fragments into the changelog."""
session.install("scriv")
session.run("scriv", "collect", "--add", "--version", *session.posargs)