Skip to content

Generate the API reference from the wheel that ships - #22

Merged
tamnd merged 1 commit into
mainfrom
reference-gen
Aug 19, 2026
Merged

Generate the API reference from the wheel that ships#22
tamnd merged 1 commit into
mainfrom
reference-gen

Conversation

@tamnd

@tamnd tamnd commented Aug 19, 2026

Copy link
Copy Markdown
Owner

The reference item of the client scorecard, for this client: a generated API reference, published with the release rather than written by hand beside it.

python tools/reference.py <directory> builds every name a reader can import, with its signature and what its docstring says, out of the installed package. The release builds the same pages from the wheel it is about to publish and uploads them, so the pages describe that wheel rather than the checkout it came out of.

The one thing an inspection cannot see through

Half of this package is compiled. zudb.connect is a function object pyo3 built, so what an inspection finds is (path, *, read_only=False, ...) with no type on anything, and the types are in _zudb.pyi where the checkers read them. Run the generator without help and it produces a complete reference in which not one signature says what it takes.

pdoc looks for a stub named after the module it is documenting, which is zudb. The stub is named after the module the names were defined in, which is zudb._zudb. So the build derives one from the other: _zudb.pyi, unchanged except that its single relative import is spelled absolutely, written under the zudb-stubs name PEP 561 reserves for a stub distributed apart from its package, and put on the path for as long as the build runs. Derived rather than written, which is the point. There is no second declaration of the public surface to keep in step, and nothing new goes in the wheel.

The relative import has to be rewritten because pdoc loads a stub with a loader of its own rather than through import, so the module has no package to be relative to and from .types import Value raises before anything is read.

What fails the build

bare() counts the public names whose signature carries no annotation, and any at all is a failure. That is the check that the overlay is still landing, and it is worth having because the failure it catches is silent: a reference that lost every type still builds, still looks finished, and is wrong about every signature on the page. Nobody reads their own generated docs closely enough to notice.

Counting is over the members a namespace declares itself, not everything it answers to. object.__eq__ takes an untyped value on every class in the language, and BaseException brings two more.

Release

A reference job, from one wheel rather than fourteen. What is being read is the public surface and every wheel in the grid has the same one, so a grid of references would be fourteen copies of one page and thirteen chances to read the wrong one.

The tags job now downloads the wheels and the sdist by name instead of taking everything the run produced. Its rule is that the directory holds the grid and nothing outside it, and the reference is a directory of HTML in the same run.

A reference written by hand beside the code is wrong by the second
release, and wrong in the way that costs the most: it looks maintained.
So this one is generated, by pdoc, from the installed package, and the
release builds it from the wheel it is about to publish rather than from
the checkout the wheel came out of.

Half of this package is compiled and that is the one thing the
inspection cannot see through. `zudb.connect` is a function object pyo3
built, so what pdoc reads off it is `(path, *, read_only=False, ...)`
and the types are in `_zudb.pyi`, where the checkers read them. pdoc
looks for a stub named after the module it is documenting, which is
`zudb`, and the stub is named after the module the names were defined
in, which is `zudb._zudb`. So `tools/reference.py` lays the stub where
pdoc looks, under the `-stubs` name PEP 561 reserves for it, deriving it
rather than writing it: there is no second declaration of the surface to
keep in step, and the only edit is the one relative import, which a stub
loaded outside the import machinery has no package to resolve.

The check on that is the part worth having. Without the overlay ten
public signatures lose every annotation, and the reference still builds,
still looks finished, and is wrong about every one of them. Nobody reads
their own generated docs closely enough to catch it, so the build fails
instead, naming the signatures it would have published bare.

`tags` now downloads the wheels by name instead of everything the run
produced, because the rule it applies is that the directory holds the
grid and nothing outside it, and the reference job puts a directory of
HTML in the same run.
@tamnd
tamnd merged commit 561428c into main Aug 19, 2026
45 of 46 checks passed
@tamnd
tamnd deleted the reference-gen branch August 19, 2026 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant