The API reference
smalldocs writes a reference page for each module of your package. A reference page lists the classes and the functions of a module, with their parameters. smalldocs reads what the code already says, so you write nothing twice:
- The types come from the annotations.
- The description of each parameter comes from the comment beside it.
- The summary comes from the docstring.
The Reference of this site is made from the code of smalldocs in this way.
Write the code
Put one parameter on each line, with its comment beside it. Put the comment for the return value after
the colon of the def line. fastcore calls these comments docments.
def add(
a: int, # The first number
b: int = 2, # The second number
) -> int: # Their sum
"Add two numbers."
return a + bsmalldocs shows other kinds of class in their own way:
- A dataclass shows its constructor, with the comment beside each field.
- A pydantic model shows its fields. The next section tells where the description of each field comes from.
- A
TypedDictshows its keys, with the comment beside each key. - A click command shows its function, with the comment beside each parameter. Then it shows a table of its options, with the help of each option. A click group shows the same.
If the __init__.py of a package defines functions or classes, the package has a page of its own.
The fields of a pydantic model
For each field, the description in the reference is:
- The
descriptionof the field, when it has one. This coversField(description="..."), and a docstring under the field when the model setsConfigDict(use_attribute_docstrings=True). - Otherwise, the comment beside the field.
- Otherwise, nothing, and
smalldocs api checkreports the gap, for examplePage.title: no description.
A field with a description and a comment is documented, and the reference shows the description. A
comment for a tool, such as # type: ignore or # noqa, is not a description.
class Page(BaseModel):
"""A page of Wikipedia: its title and the summary of its text."""
title: str # The title of the page
extract: str = Field(description="The summary: the first paragraph of the page")Each style is good for a different kind of model:
Field(description="...")is data that pydantic keeps when the program runs. It goes intomodel_json_schema(), and so into an OpenAPI schema, a FastAPI page or the tool schema of an LLM. For a model that is the schema of an API, the description does the work of the comment and more. Use it there.- The comment is lighter, and it reads like the comments of a function. For a model that only parses data, nothing else reads a description. There, the comment is enough.
Turn on the reference
Add an api section to _smalldocs.yml:
api:
packages: [mypkg] # the importable packages to document
out: api # the folder of pages, inside the site; `api` by default
root: .. # the root of the repository, from the folder of the site
source: https://github.com/me/mypkg/blob/main # each entry links to its line here
check: ["*.py", "tests/**/*.py"] # more files that `smalldocs api check` holds to the conventionIn a _quarto.yml, write the same section under smalldocs:, as smalldocs.api.
The default root is ... If the folder of the site holds pyproject.toml, the default is ..
Each build then writes a page api/<module>.qmd for each public module. It also writes
_symbols.json, the index of names. The folder out must be inside the site.
smalldocs notes the pages that it writes in the file api/.smalldocs-api. It deletes a page only if an
earlier build wrote the page and the new build did not. So a page of your own in the folder, such as
api/index.qmd, is safe.
To list the pages in the sidebar, use a glob:
website:
sidebar:
contents:
- section: Reference
contents: api/*smalldocs imports your package. So install smalldocs in the environment of the package. If the import
fails, smalldocs also looks in the root of the repository and in its src folder.
Links from the text
When the reference is on, a name in backticks becomes a link to its entry, on every page of the site.
The name must be in the reference, for example Site, inventory or smalldocs.markdown.render. A name
inside a link stays as it is. A name that the reference does not know stays as code.
Use the reference at the terminal
smalldocs api build --dir docs # write the pages and the index
smalldocs api module site --dir docs # print one module as Markdown, for people and agents
smalldocs api list --dir docs # every module, class, method and function, one line each
smalldocs api check --dir docs # what is typed and documented, and every gap; exit 1 if anycheck reports each gap in the code:
- a function without a docstring
- a parameter without a type or a docment
- a return value without a type or a docment
- a field of a pydantic model without a description or a comment
- a key of a
TypedDictwithout a comment
The globs of api.check start at the root of the repository. In them, * stays inside one folder,
and **/ is any number of folders, or none. So *.py finds the files at the root only, and
tests/**/*.py finds tests/conftest.py and tests/unit/test_x.py. check leaves out the files of
the packages in packages, because it already checks them as part of their package.
check names each file by its path from the root, such as tests/test_x.py. So the output is the same
on every computer:
tests/test_x.py:test_add: no docstringRun check in your tests, or before each commit.
Move from apidocs.py
Some projects made their reference with their own apidocs.py script and the Lua filter
linkify.lua. A Lua filter is a script that Quarto runs on each page. smalldocs builds such a project with no change:
- smalldocs runs the
pre-renderscript. Soapidocs.pywrites the pages and_symbols.jsonas before. - smalldocs sees
linkify.luainfilters, and turns on its own linkify. It does not run the Lua file. See Linkify.
To change to the api of smalldocs, do these steps:
- Add the section above to the config. Linkify is then on, with no filter.
- Remove
apidocs.pyfrompre-render. Keep the other scripts ofpre-render. - Remove
linkify.luafromfilters, and removesymbolsfrom the sectionsmalldocs. - Delete the files
apidocs.pyandlinkify.lua. - Delete the old pages in the reference folder, once. smalldocs deletes only the pages that it wrote.
For one such project, the pages that smalldocs writes are the same as before, byte for byte.