Skip to content

Commit 62f4f44

Browse files
feat: add uv readthedocs config (#424)
* feat: add uv readthedocs config Signed-off-by: Henry Schreiner <[email protected]> * Update {{cookiecutter.project_name}}/noxfile.py * style: pre-commit fixes --------- Signed-off-by: Henry Schreiner <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 17c357f commit 62f4f44

File tree

6 files changed

+76
-90
lines changed

6 files changed

+76
-90
lines changed

docs/pages/guides/docs.md

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ In order to use <https://readthedocs.org> to build, host, and preview your
238238
documentation, you must have a `.readthedocs.yaml` file {% rr RTD100 %} like
239239
this:
240240

241+
{% tabs %} {% tab uv-sphinx uv + Sphinx %}
242+
241243
<!-- [[[cog
242244
with code_fence("yaml"):
243245
print(readthedocs_yaml)
@@ -252,7 +254,31 @@ version: 2
252254
build:
253255
os: ubuntu-22.04
254256
tools:
255-
python: "3.11"
257+
python: "3.12"
258+
commands:
259+
- asdf plugin add uv
260+
- asdf install uv latest
261+
- asdf global uv latest
262+
- uv venv
263+
- uv pip install .[docs]
264+
- .venv/bin/python -m sphinx -T -b html -d docs/_build/doctrees -D
265+
language=en docs $READTHEDOCS_OUTPUT/html
266+
```
267+
<!-- prettier-ignore-end -->
268+
<!-- [[[end]]] -->
269+
270+
{% endtab %} {% tab pip-sphinx pip + Sphinx %}
271+
272+
```yaml
273+
# Read the Docs configuration file
274+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
275+
276+
version: 2
277+
278+
build:
279+
os: ubuntu-22.04
280+
tools:
281+
python: "3.12"
256282
sphinx:
257283
configuration: docs/conf.py
258284

@@ -263,8 +289,8 @@ python:
263289
extra_requirements:
264290
- docs
265291
```
266-
<!-- prettier-ignore-end -->
267-
<!-- [[[end]]] -->
292+
293+
{% endtab %} {% endtabs %}
268294
269295
This sets the Read the Docs config version (2 is required) {% rr RTD101 %}.
270296
@@ -291,50 +317,39 @@ with code_fence("python"):
291317
@nox.session(reuse_venv=True)
292318
def docs(session: nox.Session) -> None:
293319
"""
294-
Build the docs. Pass "--serve" to serve. Pass "-b linkcheck" to check links.
320+
Build the docs. Pass --non-interactive to avoid serving. First positional argument is the target directory.
295321
"""
296322
297323
parser = argparse.ArgumentParser()
298-
parser.add_argument("--serve", action="store_true", help="Serve after building")
299324
parser.add_argument(
300325
"-b", dest="builder", default="html", help="Build target (default: html)"
301326
)
327+
parser.add_argument("output", nargs="?", help="Output directory")
302328
args, posargs = parser.parse_known_args(session.posargs)
329+
serve = args.builder == "html" and session.interactive
303330
304-
if args.builder != "html" and args.serve:
305-
session.error("Must not specify non-HTML builder with --serve")
306-
307-
extra_installs = ["sphinx-autobuild"] if args.serve else []
308-
309-
session.install("-e.[docs]", *extra_installs)
310-
session.chdir("docs")
311-
312-
if args.builder == "linkcheck":
313-
session.run(
314-
"sphinx-build", "-b", "linkcheck", ".", "_build/linkcheck", *posargs
315-
)
316-
return
331+
session.install("-e.[docs]", "sphinx-autobuild")
317332
318333
shared_args = (
319334
"-n", # nitpicky mode
320335
"-T", # full tracebacks
321336
f"-b={args.builder}",
322-
".",
323-
f"_build/{args.builder}",
337+
"docs",
338+
args.output or f"docs/_build/{args.builder}",
324339
*posargs,
325340
)
326341
327-
if args.serve:
328-
session.run("sphinx-autobuild", *shared_args)
342+
if serve:
343+
session.run("sphinx-autobuild", "--open-browser", *shared_args)
329344
else:
330345
session.run("sphinx-build", "--keep-going", *shared_args)
331346
```
332347
<!-- prettier-ignore-end -->
333348
<!-- [[[end]]] -->
334349

335350
This is a more complex Nox job just because it's taking some options (the
336-
ability to build and serve instead of just build, and the ability to select the
337-
builder). The first portion is just setting up argument parsing. Then it does
351+
ability to build and serve instead of just build). The first portion is just
352+
setting up argument parsing so we can serve if building `html`. Then it does
338353
some conditional installs based on arguments (sphinx-autobuild is only needed if
339354
serving). It does an editable install of your package so that you can skip the
340355
install steps with `-R` and still get updated documentation.
@@ -367,15 +382,14 @@ def build_api_docs(session: nox.Session) -> None:
367382
"""
368383
369384
session.install("sphinx")
370-
session.chdir("docs")
371385
session.run(
372386
"sphinx-apidoc",
373387
"-o",
374-
"api/",
388+
"docs/api/",
375389
"--module-first",
376390
"--no-toc",
377391
"--force",
378-
"../src/<package-name-here>",
392+
"src/<package-name-here>",
379393
)
380394
```
381395
<!-- prettier-ignore-end -->
@@ -429,3 +443,5 @@ If you want to use Markdown instead of notebooks, you can use jupytext (see
429443
[sphinx-autodoc2]: https://sphinx-autodoc2.readthedocs.io/
430444
[`sphinx.ext.napoleon`]: https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html
431445
<!-- prettier-ignore-end -->
446+
447+
<script src="{% link assets/js/tabs.js %}"></script>

docs/pages/guides/tasks.md

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -229,41 +229,30 @@ with code_fence("python"):
229229
@nox.session(reuse_venv=True)
230230
def docs(session: nox.Session) -> None:
231231
"""
232-
Build the docs. Pass "--serve" to serve. Pass "-b linkcheck" to check links.
232+
Build the docs. Pass --non-interactive to avoid serving. First positional argument is the target directory.
233233
"""
234234
235235
parser = argparse.ArgumentParser()
236-
parser.add_argument("--serve", action="store_true", help="Serve after building")
237236
parser.add_argument(
238237
"-b", dest="builder", default="html", help="Build target (default: html)"
239238
)
239+
parser.add_argument("output", nargs="?", help="Output directory")
240240
args, posargs = parser.parse_known_args(session.posargs)
241+
serve = args.builder == "html" and session.interactive
241242
242-
if args.builder != "html" and args.serve:
243-
session.error("Must not specify non-HTML builder with --serve")
244-
245-
extra_installs = ["sphinx-autobuild"] if args.serve else []
246-
247-
session.install("-e.[docs]", *extra_installs)
248-
session.chdir("docs")
249-
250-
if args.builder == "linkcheck":
251-
session.run(
252-
"sphinx-build", "-b", "linkcheck", ".", "_build/linkcheck", *posargs
253-
)
254-
return
243+
session.install("-e.[docs]", "sphinx-autobuild")
255244
256245
shared_args = (
257246
"-n", # nitpicky mode
258247
"-T", # full tracebacks
259248
f"-b={args.builder}",
260-
".",
261-
f"_build/{args.builder}",
249+
"docs",
250+
args.output or f"docs/_build/{args.builder}",
262251
*posargs,
263252
)
264253
265-
if args.serve:
266-
session.run("sphinx-autobuild", *shared_args)
254+
if serve:
255+
session.run("sphinx-autobuild", "--open-browser", *shared_args)
267256
else:
268257
session.run("sphinx-build", "--keep-going", *shared_args)
269258
```

docs/pages/tutorials/dev-environment.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ leave the environment (or just close your shell).
9494
> You can also consider the [uv][] package, which is much, much faster version
9595
> of pip and venv implemented in Rust. Just put `uv` in front of the commands
9696
> you'd normally use; as long as you use venvs, it should be nearly the same.
97+
> You can use `--system` to mimic pip, otherwise it uses the active virtualenv
98+
> or a `.venv` folder. `uv venv` will default to a `.venv` folder.
99+
>
100+
> This also supports `--exclude-newer DATE`, which allows you to resolve as if
101+
> you were at some past point in time.
97102
98103
[uv]: https://github.com/astral-sh/uv
99104

{{cookiecutter.project_name}}/.readthedocs.yaml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ version: 2
66
build:
77
os: ubuntu-22.04
88
tools:
9-
python: "3.11"
10-
sphinx:
11-
configuration: docs/conf.py
12-
13-
python:
14-
install:
15-
- method: pip
16-
path: .
17-
extra_requirements:
18-
- docs
9+
python: "3.12"
10+
commands:
11+
- asdf plugin add uv
12+
- asdf install uv latest
13+
- asdf global uv latest
14+
- uv venv
15+
- uv pip install .[docs]
16+
- .venv/bin/python -m sphinx -T -b html -d docs/_build/doctrees -D
17+
language=en docs $READTHEDOCS_OUTPUT/html

{{cookiecutter.project_name}}/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99

1010
[![GitHub Discussion][github-discussions-badge]][github-discussions-link]
1111
{%- if cookiecutter.org | lower == "scikit-hep" %}
12-
[![Scikit-HEP][sk-badge]](https://scikit-hep.org/)
13-
{%- endif %}
12+
[![Scikit-HEP][sk-badge]](https://scikit-hep.org/) {%- endif %}
1413

1514
<!-- SPHINX-START -->
1615

{{cookiecutter.project_name}}/noxfile.py

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
from __future__ import annotations
22

33
import argparse
4-
{%- if cookiecutter.backend != "pybind11" %}
54
import shutil
65
from pathlib import Path
7-
{%- endif %}
86

97
import nox
108

11-
{% if cookiecutter.backend != "pybind11" -%}
129
DIR = Path(__file__).parent.resolve()
1310

14-
{% endif -%}
15-
1611
nox.needs_version = ">=2024.3.2"
1712
nox.options.sessions = ["lint", "pylint", "tests"]
1813
nox.options.default_venv_backend = "uv|virtualenv"
@@ -52,41 +47,30 @@ def tests(session: nox.Session) -> None:
5247
@nox.session(reuse_venv=True)
5348
def docs(session: nox.Session) -> None:
5449
"""
55-
Build the docs. Pass "--serve" to serve. Pass "-b linkcheck" to check links.
50+
Build the docs. Pass --non-interactive to avoid serving. First positional argument is the target directory.
5651
"""
5752

5853
parser = argparse.ArgumentParser()
59-
parser.add_argument("--serve", action="store_true", help="Serve after building")
6054
parser.add_argument(
6155
"-b", dest="builder", default="html", help="Build target (default: html)"
6256
)
57+
parser.add_argument("output", nargs="?", help="Output directory")
6358
args, posargs = parser.parse_known_args(session.posargs)
59+
serve = args.builder == "html" and session.interactive
6460

65-
if args.builder != "html" and args.serve:
66-
session.error("Must not specify non-HTML builder with --serve")
67-
68-
extra_installs = ["sphinx-autobuild"] if args.serve else []
69-
70-
session.install("-e.[docs]", *extra_installs)
71-
session.chdir("docs")
72-
73-
if args.builder == "linkcheck":
74-
session.run(
75-
"sphinx-build", "-b", "linkcheck", ".", "_build/linkcheck", *posargs
76-
)
77-
return
61+
session.install("-e.[docs]", "sphinx-autobuild")
7862

7963
shared_args = (
8064
"-n", # nitpicky mode
8165
"-T", # full tracebacks
8266
f"-b={args.builder}",
83-
".",
84-
f"_build/{args.builder}",
67+
"docs",
68+
args.output or f"docs/_build/{args.builder}",
8569
*posargs,
8670
)
8771

88-
if args.serve:
89-
session.run("sphinx-autobuild", *shared_args)
72+
if serve:
73+
session.run("sphinx-autobuild", "--open-browser", *shared_args)
9074
else:
9175
session.run("sphinx-build", "--keep-going", *shared_args)
9276

@@ -98,21 +82,17 @@ def build_api_docs(session: nox.Session) -> None:
9882
"""
9983

10084
session.install("sphinx")
101-
session.chdir("docs")
10285
session.run(
10386
"sphinx-apidoc",
10487
"-o",
105-
"api/",
88+
"docs/api/",
10689
"--module-first",
10790
"--no-toc",
10891
"--force",
109-
"../src/{{ cookiecutter.__project_slug }}",
92+
"src/{{ cookiecutter.__project_slug }}",
11093
)
11194

11295

113-
{%- if cookiecutter.backend != "pybind11" %}
114-
115-
11696
@nox.session
11797
def build(session: nox.Session) -> None:
11898
"""
@@ -125,5 +105,3 @@ def build(session: nox.Session) -> None:
125105

126106
session.install("build")
127107
session.run("python", "-m", "build")
128-
129-
{%- endif %}

0 commit comments

Comments
 (0)