Skip to content

Conversation

@philderbeast
Copy link
Collaborator

@philderbeast philderbeast commented Jan 3, 2026

Fixes #11381. Use uv to build the users guide.

This is faster. I measured the users guide build taking 2.05 sec versus 7.44 sec (2.96 for requirements + 4.48) beforehand, see timings.

Note

We currently need to invoke makefile pip recipes for both users-guide-requirements and users-guide targets to build the users guide but with uv used in the recipes we only need the later target.

Aside from being faster, by using uv to build the user guide:

  • We don't have to explicitly activate a python virtual environment, either in the shell or in our makefile.
  • A clean git clone can make users-guide without first make users-guide-requirements.
  • We require fewer variables, targets and recipes in the the makefiles.
  • The make users-guide recipe output is much shorter as it doesn't include the previous pip output (that can be seen in the previous make users-guide output).

I've removed requirements.in and the related requirements.txt use in the github actions, read-the-docs build and security checks. I've left the requirements.txt makefile target but use a different recipe for it:

requirements.txt:
	uv export --frozen --format requirements.txt > requirements.txt

Note

uv's lockfile (uv.lock) is created with a universal resolution and is portable across platforms.
SOURCE: https://docs.astral.sh/uv/concepts/resolution/#platform-specific-resolution

I moved the CVE comments from requirements.in to pyproject.toml.

The security checks remain but its recipe I've changed to use uvx skjold and uv pip list:

.PHONY: check-requirements
check-requirements:
...
	uvx skjold -c pyproject.toml config \
	&& uv pip list --format freeze | uvx skjold -c pyproject.toml audit

uvx skjold -c pyproject.toml config shows the configuration for skjold, kept in pyproject.toml:

$ uvx skjold -c pyproject.toml config
sources: ['github', 'gemnasium', 'pyup']
report_only: False
report_format: cli
verbose: False
cache_dir: .skjold_cache
cache_expires: 43200
ignore_file: .skjoldignore

uv pip list --format freeze is the equivalent of what we had in requirements.txt minus the comments, a list of version equalities:

$ uv pip list --format freeze
alabaster==1.0.0
...
urllib3==2.6.2

  • Patches conform to the coding conventions.
  • Is this a PR that fixes CI? If so, it will need to be backported to older cabal release branches (ask maintainers for directions).

@philderbeast philderbeast marked this pull request as draft January 3, 2026 16:06
@philderbeast philderbeast force-pushed the replace/pip-with-uv branch 8 times, most recently from 0a068fd to 0937ded Compare January 5, 2026 12:37
@ulysses4ever
Copy link
Collaborator

I will unsubsccribe from this for now but feel free to explicitly ping me when you need input. I encourage to first discuss the objective of this in ##11381 though.

@philderbeast philderbeast force-pushed the replace/pip-with-uv branch 5 times, most recently from 0b4fd70 to 667aa30 Compare January 5, 2026 18:20
@philderbeast
Copy link
Collaborator Author

philderbeast commented Jan 5, 2026

Build times

Comparing the times for ways of building the docs.

  • With uv
$ uv cache clean
Clearing cache at: /home/philderbeast/.cache/uv
Removed 3883 files (72.9MiB)
   
$ time make users-guide --always-make
...
________________________________________________________
Executed in    2.05 secs    fish           external
   usr time    1.99 secs  568.00 micros    1.99 secs
   sys time    0.07 secs   89.00 micros    0.07 secs
  • Currently without a fix for python-3.13
$ time make users-guide --always-make
make -C doc users-guide
make[1]: Entering directory '/home/philderbeast/dev/src/cabalism/cabal/doc'
python3 -m venv ../.python-sphinx-virtualenv
(. ../.python-sphinx-virtualenv/bin/activate)
mkdir -p ../dist-newstyle/doc/users-guide
(. ../.python-sphinx-virtualenv/bin/activate
  && pip install -r requirements.txt
  && sphinx-build -n -W --keep-going -E . ../dist-newstyle/doc/users-guide)
ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements.txt'
make[1]: *** [Makefile:40: ../dist-newstyle/doc/users-guide/index.html] Error 1
make[1]: Leaving directory '/home/philderbeast/dev/src/cabalism/cabal/doc'
make: *** [Makefile:287: users-guide] Error 2

________________________________________________________
Executed in    1.33 secs    fish           external
   usr time    1.25 secs   42.11 millis    1.21 secs
   sys time    0.12 secs   12.12 millis    0.11 secs
$ time make users-guide-requirements
...
________________________________________________________
Executed in    2.96 secs    fish           external
   usr time    1.94 secs  912.00 micros    1.94 secs
   sys time    0.23 secs    0.00 micros    0.23 secs

$ time make users-guide --always-make
...
________________________________________________________
Executed in    4.48 secs    fish           external
   usr time    3.91 secs  612.00 micros    3.91 secs
   sys time    0.24 secs   96.00 micros    0.24 secs

@ulysses4ever
Copy link
Collaborator

Rebasing on master should solve the ci issue

@philderbeast philderbeast force-pushed the replace/pip-with-uv branch 4 times, most recently from 3f25b11 to 8d29392 Compare January 9, 2026 22:47
@philderbeast
Copy link
Collaborator Author

philderbeast commented Jan 10, 2026

With the current setup, we cannot just make users-guide:

$ gh repo clone haskell/cabal
$ cd cabal

$ time make users-guide
make -C doc users-guide
make[1]: Entering directory '/home/.../cabal/doc'
python3 -m venv ../.python-sphinx-virtualenv
(. ../.python-sphinx-virtualenv/bin/activate)
mkdir -p ../dist-newstyle/doc/users-guide
(. ../.python-sphinx-virtualenv/bin/activate && pip install -r requirements.txt
  && sphinx-build -n -W --keep-going -E . ../dist-newstyle/doc/users-guide)
ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements.txt'
make[1]: *** [Makefile:40: ../dist-newstyle/doc/users-guide/index.html] Error 1
make[1]: Leaving directory '/home/.../cabal/doc'
make: *** [Makefile:287: users-guide] Error 2

________________________________________________________
Executed in    1.34 secs    fish           external
   usr time    1.18 secs    0.16 millis    1.18 secs
   sys time    0.15 secs    1.09 millis    0.14 secs

We need to make users-guide-requirements manually before hand:

$ time make users-guide-requirements
make -C doc users-guide-requirements
make[1]: Entering directory '/home/.../cabal/doc'
. ../.python-sphinx-virtualenv/bin/activate \
  && pip install --upgrade 'pip!=25.3' \
  && pip install pip-tools \
  && pip-compile requirements.in
Requirement already satisfied: pip!=25.3 in
  /home/.../cabal/.python-sphinx-virtualenv/lib/python3.13/site-packages (25.1.1)
Collecting pip!=25.3
  Using cached pip-25.2-py3-none-any.whl.metadata (4.7 kB)
Using cached pip-25.2-py3-none-any.whl (1.8 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 25.1.1
    Uninstalling pip-25.1.1:
      Successfully uninstalled pip-25.1.1
Successfully installed pip-25.2
Collecting pip-tools
  Using cached pip_tools-7.5.2-py3-none-any.whl.metadata (26 kB)
Collecting build>=1.0.0 (from pip-tools)
  Downloading build-1.4.0-py3-none-any.whl.metadata (5.8 kB)
Collecting click>=8 (from pip-tools)
  Using cached click-8.3.1-py3-none-any.whl.metadata (2.6 kB)
Requirement already satisfied: pip>=22.2 in
  /home/.../cabal/.python-sphinx-virtualenv/lib/python3.13/site-packages (from pip-tools) (25.2)
Collecting pyproject_hooks (from pip-tools)
  Using cached pyproject_hooks-1.2.0-py3-none-any.whl.metadata (1.3 kB)
Collecting setuptools (from pip-tools)
  Using cached setuptools-80.9.0-py3-none-any.whl.metadata (6.6 kB)
Collecting wheel (from pip-tools)
  Using cached wheel-0.45.1-py3-none-any.whl.metadata (2.3 kB)
Collecting packaging>=24.0 (from build>=1.0.0->pip-tools)
  Using cached packaging-25.0-py3-none-any.whl.metadata (3.3 kB)
Using cached pip_tools-7.5.2-py3-none-any.whl (66 kB)
Downloading build-1.4.0-py3-none-any.whl (24 kB)
Using cached click-8.3.1-py3-none-any.whl (108 kB)
Using cached packaging-25.0-py3-none-any.whl (66 kB)
Using cached pyproject_hooks-1.2.0-py3-none-any.whl (10 kB)
Using cached setuptools-80.9.0-py3-none-any.whl (1.2 MB)
Using cached wheel-0.45.1-py3-none-any.whl (72 kB)
Installing collected packages: wheel, setuptools, pyproject_hooks, packaging, click, build, pip-tools
Successfully installed build-1.4.0 click-8.3.1 packaging-25.0 pip-tools-7.5.2
  pyproject_hooks-1.2.0 setuptools-80.9.0 wheel-0.45.1

[notice] A new release of pip is available: 25.2 -> 25.3
[notice] To update, run: pip install --upgrade pip
WARNING: --strip-extras is becoming the default in version 8.0.0. To silence this warning,
  either use --strip-extras to opt into the new default
  or use --no-strip-extras to retain the existing behavior.
#
# This file is autogenerated by pip-compile with Python 3.13
# by the following command:
#
#    pip-compile requirements.in
#
alabaster==1.0.0
    # via sphinx
babel==2.17.0
    # via sphinx
certifi==2026.1.4
    # via
    #   -r requirements.in
    #   requests
charset-normalizer==3.4.4
    # via requests
docutils==0.21.2
    # via
    #   sphinx
    #   sphinx-jsonschema
    #   sphinx-rtd-theme
idna==3.11
    # via
    #   -r requirements.in
    #   requests
imagesize==1.4.1
    # via sphinx
jinja2==3.1.6
    # via
    #   -r requirements.in
    #   sphinx
jsonpointer==3.0.0
    # via sphinx-jsonschema
markupsafe==3.0.3
    # via jinja2
packaging==25.0
    # via sphinx
pygments==2.19.2
    # via
    #   -r requirements.in
    #   sphinx
pyyaml==6.0.3
    # via sphinx-jsonschema
requests==2.32.5
    # via
    #   -r requirements.in
    #   sphinx
    #   sphinx-jsonschema
roman-numerals==4.1.0
    # via roman-numerals-py
roman-numerals-py==4.1.0
    # via sphinx
snowballstemmer==3.0.1
    # via sphinx
sphinx==8.2.3
    # via
    #   -r requirements.in
    #   sphinx-rtd-theme
    #   sphinxcontrib-jquery
    #   sphinxnotes-strike
sphinx-jsonschema==1.19.2
    # via -r requirements.in
sphinx-rtd-theme==3.0.2
    # via -r requirements.in
sphinxcontrib-applehelp==2.0.0
    # via sphinx
sphinxcontrib-devhelp==2.0.0
    # via sphinx
sphinxcontrib-htmlhelp==2.1.0
    # via sphinx
sphinxcontrib-jquery==4.1
    # via sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
    # via sphinx
sphinxcontrib-qthelp==2.0.0
    # via sphinx
sphinxcontrib-serializinghtml==2.0.0
    # via sphinx
sphinxnotes-strike==2.0
    # via -r requirements.in
urllib3==2.6.3
    # via
    #   -r requirements.in
    #   requests
make[1]: Leaving directory '/home/.../cabal/doc'

________________________________________________________
Executed in    3.44 secs    fish           external
   usr time    2.22 secs    0.26 millis    2.22 secs
   sys time    0.25 secs    1.12 millis    0.25 secs

That done, we can make users-guide:

$ time make users-guide
make -C doc users-guide
make[1]: Entering directory '/home/.../cabal/doc'
mkdir -p ../dist-newstyle/doc/users-guide
(. ../.python-sphinx-virtualenv/bin/activate
  && pip install -r requirements.txt
  && sphinx-build -n -W --keep-going -E . ../dist-newstyle/doc/users-guide)
Collecting alabaster==1.0.0 (from -r requirements.txt (line 7))
  Using cached alabaster-1.0.0-py3-none-any.whl.metadata (2.8 kB)
Collecting babel==2.17.0 (from -r requirements.txt (line 9))
  Using cached babel-2.17.0-py3-none-any.whl.metadata (2.0 kB)
Collecting certifi==2026.1.4 (from -r requirements.txt (line 11))
  Using cached certifi-2026.1.4-py3-none-any.whl.metadata (2.5 kB)
Collecting charset-normalizer==3.4.4 (from -r requirements.txt (line 15))
  Using cached charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64
  .whl.metadata (37 kB)
Collecting docutils==0.21.2 (from -r requirements.txt (line 17))
  Using cached docutils-0.21.2-py3-none-any.whl.metadata (2.8 kB)
Collecting idna==3.11 (from -r requirements.txt (line 22))
  Using cached idna-3.11-py3-none-any.whl.metadata (8.4 kB)
Collecting imagesize==1.4.1 (from -r requirements.txt (line 26))
  Using cached imagesize-1.4.1-py2.py3-none-any.whl.metadata (1.5 kB)
Collecting jinja2==3.1.6 (from -r requirements.txt (line 28))
  Using cached jinja2-3.1.6-py3-none-any.whl.metadata (2.9 kB)
Collecting jsonpointer==3.0.0 (from -r requirements.txt (line 32))
  Using cached jsonpointer-3.0.0-py2.py3-none-any.whl.metadata (2.3 kB)
Collecting markupsafe==3.0.3 (from -r requirements.txt (line 34))
  Using cached markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64
  .whl.metadata (2.7 kB)
Requirement already satisfied: packaging==25.0 in
  /home/.../cabal/.python-sphinx-virtualenv/lib/python3.13/site-packages
  (from -r requirements.txt (line 36)) (25.0)
Collecting pygments==2.19.2 (from -r requirements.txt (line 38))
  Using cached pygments-2.19.2-py3-none-any.whl.metadata (2.5 kB)
Collecting pyyaml==6.0.3 (from -r requirements.txt (line 42))
  Using cached pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64.whl.metadata (2.4 kB)
Collecting requests==2.32.5 (from -r requirements.txt (line 44))
  Using cached requests-2.32.5-py3-none-any.whl.metadata (4.9 kB)
Collecting roman-numerals==4.1.0 (from -r requirements.txt (line 49))
  Using cached roman_numerals-4.1.0-py3-none-any.whl.metadata (3.3 kB)
Collecting roman-numerals-py==4.1.0 (from -r requirements.txt (line 51))
  Using cached roman_numerals_py-4.1.0-py3-none-any.whl.metadata (561 bytes)
Collecting snowballstemmer==3.0.1 (from -r requirements.txt (line 53))
  Using cached snowballstemmer-3.0.1-py3-none-any.whl.metadata (7.9 kB)
Collecting sphinx==8.2.3 (from -r requirements.txt (line 55))
  Using cached sphinx-8.2.3-py3-none-any.whl.metadata (7.0 kB)
Collecting sphinx-jsonschema==1.19.2 (from -r requirements.txt (line 61))
  Using cached sphinx_jsonschema-1.19.2-py3-none-any.whl
Collecting sphinx-rtd-theme==3.0.2 (from -r requirements.txt (line 63))
  Using cached sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl.metadata (4.4 kB)
Collecting sphinxcontrib-applehelp==2.0.0 (from -r requirements.txt (line 65))
  Using cached sphinxcontrib_applehelp-2.0.0-py3-none-any.whl.metadata (2.3 kB)
Collecting sphinxcontrib-devhelp==2.0.0 (from -r requirements.txt (line 67))
  Using cached sphinxcontrib_devhelp-2.0.0-py3-none-any.whl.metadata (2.3 kB)
Collecting sphinxcontrib-htmlhelp==2.1.0 (from -r requirements.txt (line 69))
  Using cached sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl.metadata (2.3 kB)
Collecting sphinxcontrib-jquery==4.1 (from -r requirements.txt (line 71))
  Using cached sphinxcontrib_jquery-4.1-py2.py3-none-any.whl.metadata (2.6 kB)
Collecting sphinxcontrib-jsmath==1.0.1 (from -r requirements.txt (line 73))
  Using cached sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl.metadata (1.4 kB)
Collecting sphinxcontrib-qthelp==2.0.0 (from -r requirements.txt (line 75))
  Using cached sphinxcontrib_qthelp-2.0.0-py3-none-any.whl.metadata (2.3 kB)
Collecting sphinxcontrib-serializinghtml==2.0.0 (from -r requirements.txt (line 77))
  Using cached sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl.metadata (2.4 kB)
Collecting sphinxnotes-strike==2.0 (from -r requirements.txt (line 79))
  Using cached sphinxnotes_strike-2.0-py3-none-any.whl.metadata (3.0 kB)
Collecting urllib3==2.6.3 (from -r requirements.txt (line 81))
  Using cached urllib3-2.6.3-py3-none-any.whl.metadata (6.9 kB)
Using cached alabaster-1.0.0-py3-none-any.whl (13 kB)
Using cached babel-2.17.0-py3-none-any.whl (10.2 MB)
Using cached certifi-2026.1.4-py3-none-any.whl (152 kB)
Using cached charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64.whl (153 kB)
Using cached docutils-0.21.2-py3-none-any.whl (587 kB)
Using cached idna-3.11-py3-none-any.whl (71 kB)
Using cached imagesize-1.4.1-py2.py3-none-any.whl (8.8 kB)
Using cached jinja2-3.1.6-py3-none-any.whl (134 kB)
Using cached jsonpointer-3.0.0-py2.py3-none-any.whl (7.6 kB)
Using cached markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64.whl (22 kB)
Using cached pygments-2.19.2-py3-none-any.whl (1.2 MB)
Using cached pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64
  .manylinux_2_17_x86_64
  .manylinux_2_28_x86_64.whl (801 kB)
Using cached requests-2.32.5-py3-none-any.whl (64 kB)
Using cached urllib3-2.6.3-py3-none-any.whl (131 kB)
Using cached roman_numerals-4.1.0-py3-none-any.whl (7.7 kB)
Using cached roman_numerals_py-4.1.0-py3-none-any.whl (4.5 kB)
Using cached snowballstemmer-3.0.1-py3-none-any.whl (103 kB)
Using cached sphinx-8.2.3-py3-none-any.whl (3.6 MB)
Using cached sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl (7.7 MB)
Using cached sphinxcontrib_jquery-4.1-py2.py3-none-any.whl (121 kB)
Using cached sphinxcontrib_applehelp-2.0.0-py3-none-any.whl (119 kB)
Using cached sphinxcontrib_devhelp-2.0.0-py3-none-any.whl (82 kB)
Using cached sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl (98 kB)
Using cached sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl (5.1 kB)
Using cached sphinxcontrib_qthelp-2.0.0-py3-none-any.whl (88 kB)
Using cached sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl (92 kB)
Using cached sphinxnotes_strike-2.0-py3-none-any.whl (4.8 kB)
Installing collected packages: urllib3, sphinxcontrib-serializinghtml, sphinxcontrib-qthelp,
  sphinxcontrib-jsmath, sphinxcontrib-htmlhelp, sphinxcontrib-devhelp, sphinxcontrib-applehelp,
  snowballstemmer, roman-numerals, pyyaml, pygments, markupsafe, jsonpointer, imagesize,
  idna, docutils, charset-normalizer, certifi, babel, alabaster, roman-numerals-py, requests,
  jinja2, sphinx-jsonschema, sphinx, sphinxnotes-strike, sphinxcontrib-jquery, sphinx-rtd-theme
Successfully installed alabaster-1.0.0 babel-2.17.0 certifi-2026.1.4 charset-normalizer-3.4.4
  docutils-0.21.2 idna-3.11 imagesize-1.4.1 jinja2-3.1.6 jsonpointer-3.0.0 markupsafe-3.0.3
  pygments-2.19.2 pyyaml-6.0.3 requests-2.32.5 roman-numerals-4.1.0 roman-numerals-py-4.1.0
  snowballstemmer-3.0.1 sphinx-8.2.3 sphinx-jsonschema-1.19.2 sphinx-rtd-theme-3.0.2
  sphinxcontrib-applehelp-2.0.0 sphinxcontrib-devhelp-2.0.0 sphinxcontrib-htmlhelp-2.1.0
  sphinxcontrib-jquery-4.1 sphinxcontrib-jsmath-1.0.1 sphinxcontrib-qthelp-2.0.0
  sphinxcontrib-serializinghtml-2.0.0 sphinxnotes-strike-2.0 urllib3-2.6.3

[notice] A new release of pip is available: 25.2 -> 25.3
[notice] To update, run: pip install --upgrade pip
Running Sphinx v8.2.3
loading translations [en]... done
Converting `source_suffix = '.rst'` to `source_suffix = {'.rst': 'restructuredtext'}`.
building [mo]: targets for 0 po files that are out of date
writing output... 
building [html]: targets for 29 source files that are out of date
updating environment: [new config] 29 added, 0 changed, 0 removed
reading sources... [100%] version-control-fields
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
copying assets... 
copying static files... 
Writing evaluated template result to /home/.../doc/users-guide/_static/basic.css
Writing evaluated template result to /home/.../doc/users-guide/_static/documentation_options.js
Writing evaluated template result to /home/.../doc/users-guide/_static/language_data.js
Writing evaluated template result to /home/.../doc/users-guide/_static/js/versions.js
copying static files: done
copying extra files... 
copying extra files: done
copying assets: done
writing output... [100%] version-control-fields
generating indices... genindex cabal-syntax-quicklinks done
writing additional pages... search opensearch done
dumping search index in English (code: en)... done
dumping object inventory... done
build succeeded.

The HTML pages are in ../dist-newstyle/doc/users-guide.
make[1]: Leaving directory '/home/.../cabal/doc'

________________________________________________________
Executed in    4.81 secs    fish           external
   usr time    3.68 secs    0.29 millis    3.68 secs
   sys time    0.28 secs    1.12 millis    0.28 secs

@philderbeast philderbeast force-pushed the replace/pip-with-uv branch 3 times, most recently from 87e8afe to c558f87 Compare January 10, 2026 22:15
@philderbeast philderbeast marked this pull request as ready for review January 10, 2026 22:15
- Add packaging dependency
- Use uv with read the docs
- Use only uv sync & uv run
- Remove python|install|requirements
- Remove UV_PROJECT_ENVIRONMENT
- Custom rtd build for html
- uv sync --project doc
- Commit doc/requirements.txt
- Use uvx skjold
- Use uv export for requirements.txt
- Use uv run sphinx-build
- Install uv
- Remove virtual environment
- Add .venv to exclude_patterns
- Move CVE suggestions to comment
- Remove requirements.txt related
- Change log entry
- Inline $(SPHINXCMD)
- Replace pip-tools with uv in readme
- Show use of uv pip list --outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Could we use uv for building the users guide?

3 participants