Add python_version input to doc build workflows - #808
Merged
Conversation
The build venv is created with a bare `uv venv`, which picks the runner's system Python (3.10 on ubuntu-22.04). Packages that require a newer Python (e.g. reachy_mini needs >=3.11) then fail to install: "current Python version (3.10.x) does not satisfy Python>=3.11". Add an optional `python_version` input, passed to `uv venv --python` so uv provisions that version. Unset by default, preserving current behavior for every other caller. Assisted-by: Claude:claude-opus-4-8
pkooij
added a commit
to huggingface/lerobot
that referenced
this pull request
Aug 7, 2026
The shared doc-builder workflows create their virtualenv with the runner's
system Python, which is 3.10.12 on ubuntu-22.04. lerobot requires >=3.12, so
the build died during "Setup environment":
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.10.12) does not satisfy
Python>=3.12 and lerobot==0.6.2 depends on Python>=3.12 ...
That step runs before `pre_command`, so the real install this workflow already
performs never got the chance to run. There was no fix available on the caller
side either: `env:` does not propagate into a reusable workflow, so `UV_PYTHON`
is unavailable, and `uv venv` runs in the runner workspace root rather than the
checkout, so a `.python-version` file cannot reach it. The non-light fallback
(`uv pip install "./pkg[dev]"`) fails identically, so this is not specific to
the mock-deps path — it blocks any package requiring 3.12+.
huggingface/doc-builder#808 adds a `python_version` input to both build
workflows, which this passes. Pins move to that merge commit, picking up three
unrelated fixes in the same range (#810, #811, #812); the upload workflow is
unchanged there and is bumped only to keep all three pins on one SHA.
5 tasks
FabienDanieau
added a commit
to pollen-robotics/reachy_mini
that referenced
this pull request
Aug 7, 2026
The python_version input was added on a fork branch while it was under review, so both doc workflows were temporarily pinned to pollen-robotics/doc-builder@add-python-version-input. It is now merged upstream (huggingface/doc-builder#808), so drop the fork pin and go back to huggingface/doc-builder@main. The fork branch held nothing else pollen-specific, and upstream main has since moved ahead (the version list is read from the doc bucket instead of the legacy dataset), so this also picks up those fixes. Assisted-by: Claude:claude-opus-5[1m]
pkooij
added a commit
to huggingface/lerobot
that referenced
this pull request
Aug 7, 2026
* docs: add API documentation infrastructure
LeRobot's documentation build passes `--not_python_module`, which tells
doc-builder there is no importable Python package and disables `[[autodoc]]`
entirely. The result is that all 90+ pages are hand-written guides and there is
no generated API reference at all.
This is the machinery to change that. It deliberately contains no docstring
changes of its own — every docstring edit lives in the follow-up PR, so this
one can be reviewed as tooling and configuration alone.
**The standard.** `docs/source/writing_docstrings.mdx` is the contract: Google
section headers with Hugging Face type formatting, the machine-checked argument
line, `**Attributes**:`, doc-builder cross-references, fenced doctest examples.
It also records three behaviours that are not discoverable from the source and
were verified against a local build: `[[autodoc]]` silently skips members with
no docstring; doc-builder does not inherit docstrings from base classes, so a
registered config shim whose body is `pass` renders every field with no
description; and module-level aliases resolve to the canonical class.
**Autodoc turned on**, with two changes that are not obvious:
- `--version main` on the main-docs job. Without `--not_python_module`,
doc-builder resolves the version from `lerobot.__version__` and only maps it
to the default branch when it contains "dev". transformers relies on that;
our main carries 0.6.2. Verified by building both ways — dropping the flag
alone would publish the main docs to /lerobot/v0.6.2/ instead of
/lerobot/main/ and disable notebook building.
- `pre_command` on both jobs. doc-builder ships a mock-deps registry entry for
lerobot, so the reusable workflow takes its light-install path, which cannot
import the package. The heavy dependencies cannot be mocked either: draccus
runs `register_subclass` at import time and `processor/converters.py` calls
`functools.singledispatch.register(torch.Tensor)`, which needs a real class.
`[dataset]` is the only extra required.
Workflow triggers gain `src/**`, since the reference is now generated from
docstrings. `docs/source/api/` is excluded from the prettier hook, which reads
`[[autodoc]]` member lists as lazy paragraph continuations and joins a ten-entry
list onto one line.
Nine API reference pages, scaffolded with each module's base class.
**Doctests.** `LeRobotDocTestParser` is mandatory rather than optional here:
ruff's `docstring-code-format = true` drops the blank line before a closing
fence, after which stdlib's `_EXAMPLE_RE` reads the fence as expected output and
every example with output fails. It is written against the installed pytest
rather than copied from transformers, whose version predates pytest 9's
`import_path` signature and its own fix for the `@property` line-number bug.
`preprocess_string` also diverges: the upstream fenced-block split puts a
single-line example's code in a chunk with no `>>>` in it, so neither the CUDA
skip nor the `+IGNORE_RESULT` injection fires for it.
**Checkers.** `utils/check_docstrings.py` is the ~300-line core of the
2203-line transformers original; the `@auto_docstring` system, modular
propagation, GitPython and `checkers.py` are not ported.
`utils/check_config_docstrings.py` checks that every registered robot config
documents its port and calibration semantics.
**Gates**, all set to values that pass today: ruff `D` with per-file-ignores
per unconverted module, `interrogate` at `fail-under = 52` against a measured
52.1%, and Makefile targets wired into the quality workflow. The doctest
allowlist ships empty and the `doctest` target handles that, because the files
carrying runnable examples arrive with the docstring PR.
* ci: build the docs on Python 3.12
The shared doc-builder workflows create their virtualenv with the runner's
system Python, which is 3.10.12 on ubuntu-22.04. lerobot requires >=3.12, so
the build died during "Setup environment":
× No solution found when resolving dependencies:
╰─▶ Because the current Python version (3.10.12) does not satisfy
Python>=3.12 and lerobot==0.6.2 depends on Python>=3.12 ...
That step runs before `pre_command`, so the real install this workflow already
performs never got the chance to run. There was no fix available on the caller
side either: `env:` does not propagate into a reusable workflow, so `UV_PYTHON`
is unavailable, and `uv venv` runs in the runner workspace root rather than the
checkout, so a `.python-version` file cannot reach it. The non-light fallback
(`uv pip install "./pkg[dev]"`) fails identically, so this is not specific to
the mock-deps path — it blocks any package requiring 3.12+.
huggingface/doc-builder#808 adds a `python_version` input to both build
workflows, which this passes. Pins move to that merge commit, picking up three
unrelated fixes in the same range (#810, #811, #812); the upload workflow is
unchanged there and is bumped only to keep all three pins on one SHA.
* chore: sort imports in vla_jepa tests
Enabling pydocstyle in the previous commit changes how ruff determines where a
module's import block ends, which makes I001 fire on three vla_jepa tests that
were clean before. The blank line between the `conftest` and `lerobot` imports
is the trigger: both are first-party, so isort wants them in one contiguous
block, and the docstring-aware analysis is what makes it notice.
These files are unrelated to the API reference, so the fix is only to satisfy
the new gate.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds an optional
python_versioninput to both reusable build workflows (build_main_documentation.ymlandbuild_pr_documentation.yml). When set, the build venv is created with that Python:uv venv ${{ inputs.python_version && format('--python {0}', inputs.python_version) || '' }}Unset by default → bare
uv venv, i.e. no behavior change for any existing caller.Why
The build venv is currently created with a bare
uv venv, which picks the runner's system Python — 3.10 onubuntu-22.04. A documented package that requires a newer Python then can't be installed, and the build fails during "Setup environment":There's no way for a caller to select the interpreter today:
pre_commandruns after the venv is created, and a reusable workflow can't inherit env likeUV_PYTHONfrom the caller. This surfaced building the pollen-robotics/reachy_mini docs (requires-python = ">=3.11").uvprovisions the requested version automatically (the job already exportsUV_PYTHON_INSTALL_DIR), so callers just pass e.g.python_version: "3.11".