Sphinx documentation scripts used by our projects:
- The
.readthedocs.yamlfile is a configuration file used by readthedocs.org. - The
autodoc_typehints.pyscript is a custom Sphinx plugin to automatically document types for attributes and function signatures, based on Python's type hints. - The
docsfolder contains all documentation-building scripts.
Additionally, the docs/intersphinx folder contains object inventories for our most commonly used libraries, for use by the intersphinx extension: see Intersphinx Inventories below.
When adding these scripts to a project, replace the following placeholders
throughout the docs folder (a project-wide find-and-replace is the
quickest way):
| Placeholder | Replace with | Example |
|---|---|---|
PROJECT_NAME |
Project/distribution name, as published on PyPI. | example-project |
PACKAGE_NAME |
Top-level importable package name. | example_project |
COPYRIGHT_HOLDER |
Copyright holder shown in the docs footer. | 2025, Example Org |
AUTHOR_NAME |
Author name shown in the docs metadata. | Example Org |
GITHUB_ORG |
GitHub organization or user that owns the repository. | example-org |
The placeholders appear in the following files:
docs/conf.py:project(PROJECT_NAME),copyright(COPYRIGHT_HOLDER) andauthor(AUTHOR_NAME). Also setreleaseandversionto the desired version numbers.docs/make-api.json:pkg_name(PACKAGE_NAME).docs/api-toc.rst: theapi/PACKAGE_NAMEentry. Add any other module names here (e.g.api/PACKAGE_NAME.SCRIPT_MODULE_NAMEfor a script package).docs/index.rst: the title and GitHub repository link (PROJECT_NAME,GITHUB_ORG). Write a brief description of the project (e.g. the description at the start of the GitHub README file).docs/getting-started.rst: the PyPI release link, thepip installinstructions and the GitHub repository link (PROJECT_NAME,GITHUB_ORG). Write an introductory description of the project, with basic usage instructions/examples.
In docs/requirements.txt, replace PROJECT_NAME
with the project itself and add any further package dependencies needed to
import it while building the documentation.
Building the documentation requires Python 3.14 or later: the autodoc_typehints.py plugin reads string-form type annotations through the annotationlib module, so that it works whether a project uses from __future__ import annotations or the lazy annotations that are the default from Python 3.14 onwards. The documented project itself may target any Python version it likes.
To make the documentation, run the following commands from the docs folder:
make api
make clean
make html
The make-api-clean-html.bat can be run from the docs folder to this effect.
Missing references can be skipped by adding the full name to the skip_missing_references set in docs/conf.py.
The docs/intersphinx folder bundles object inventories for our most commonly used libraries, so that documentation builds resolve references to them without downloading anything.
Only the Python inventory is enabled by default, in the intersphinx_mapping dictionary in docs/conf.py, because it is the one inventory essentially every project needs.
To link against another library, uncomment its entry there and copy the matching .inv file into the project's own intersphinx folder.
The inventories go stale as the libraries they describe publish new versions.
The fetch-intersphinx.py script re-downloads them from the documentation sites recorded in docs/intersphinx/sources.json, either all of them or a named few:
python docs/fetch-intersphinx.py # refresh every inventory
python docs/fetch-intersphinx.py numpy scipy # refresh selected ones
An inventory is only written if its download succeeded, so a failed fetch leaves the bundled copy untouched.
To bundle a library which is not yet covered, add an entry to sources.json giving the base URL of its documentation and the inventory filename to write, then run the script for it.
The following keys can be set in docs/make-api.json:
"type_aliases": dict[str, list[str]],
"include_members": dict[str, list[str]],
"exclude_members": dict[str, list[str]],
"include_modules": list[str],
"exclude_modules": list[str],
"member_fullnames": dict[str, dict[str, str]],
"special_class_members": dict[str, list[str]],
"manual_doc": dict[str, list[str]],Type aliases declared with the PEP 695 type statement (e.g. type Vec = list[float]) are detected automatically and included in the documentation, attributed to the module that defines them. For these, no configuration is needed.
They are documented with Sphinx's autotype directive, which renders the alias together with the type it stands for, as type Vec = list[float].
Legacy aliases are documented with autodata instead, because they are ordinary module-level values rather than typing.TypeAliasType instances.
The type_aliases key remains available for aliases that auto-detection cannot see — most commonly legacy aliases declared as X: TypeAlias = ... or as bare assignments. An entry maps a module name to a list of module-level type alias names to include. Entries listed here take precedence over auto-detected ones, so they also serve to pin the module a given alias name is attributed to when it is re-exported from several modules.
Including a type alias (whether auto-detected or listed here) impacts documentation more broadly, making it available to docstrings for other modules.
The following usage example is adapted from tensorsat:
"type_aliases": {
"tensorsat.diagrams": [
"Box", "Shape", "Slot", "Block", "Port", "Wire",
"Slots", "Ports", "Wires", "BoxClass"
],
"tensorsat.lang.fin_rel": [
"Size", "El", "Point", "NumpyUInt8Array", "FinSetShape"
],
"tensorsat.lib.sat": ["Clause", "CNFDiagramMode"],
"tensorsat.viz.diagrams": ["DiagramGraphNodeKind", "DiagramGraphNode"],
"tensorsat.contractions": ["Contraction"],
"tensorsat.contractions.simple": [
"ContractionPath", "Contract2Args", "OptEinsumOptimize"
],
"tensorsat.contractions.cotengra": [
"CotengraOptimizer", "ReusableCotengraOptimizer"
]
}The include_members key can be set to a dictionary, where an entry maps a module name to a list of module-level names which should be explicitly included in the documentation, because Autodoc wouldn't otherwise recognise them.
Typically, this is used to force Sphinx to document exported module-level variables/constants, or to include protected/private members that should nonetheless be publicly documented.
The following usage example is adapted from tensorsat:
"include_members": {
"tensorsat.lib.bincirc": [
"bit",
"not_",
"and_",
"or_",
"xor_",
"bit_0",
"bit_1",
"bit_unk",
"binop_labels"
]
}The exclude_members key can be set to a dictionary, where an entry maps a module name to a list of module-level type alias names which should be explicitly excluded from the documentation.
Typically, these are members which are public but shouldn't be publicly documented, e.g. because they are not user-facing.
The following usage example is adapted from multiformats:
"exclude_members": {
"multiformats.multicodec": ["build_multicodec_tables"],
"multiformats.multibase": ["build_multibase_tables"],
"multiformats.multibase.raw": ["RawEncoder", "RawDecoder"],
"multiformats.cid": ["CIDVersionNumbers", "byteslike"],
"multiformats.multiaddr.raw": [
"ip4_encoder", "ip4_decoder", "ip6_encoder",
"ip6_decoder", "tcp_udp_encoder", "tcp_udp_decoder"
]
},The include_modules key can be set to a list of module names to be explicitly included in the documentation, because because Autodoc wouldn't otherwise recognise them.
The exclude_modules key can be set to a list of module names to be explicitly excluded from the documentation.
Typically, these are utility modules which shouldn't be documented in the public API.
The following usage example is adapted from dag-cbor:
"exclude_modules": [
"dag_cbor.decoding._err",
"dag_cbor.decoding._err_utils",
"dag_cbor.decoding._stream"
],The member_fullnames key can be set to a dictionary, where an entry maps a module name to a dictionary of member fullnames.
Each entry in a dictionary of member fullnames maps the local name exported by the module to the corresponding full name, qualified to indicate where the exported member was originally defined.
Typically, this is used to document constants exported by modules but defined in sub-modules.
The following usage example is adapted from bases:
"member_fullnames": {
"bases": {
"base2": "bases.encoding.base2",
"base8": "bases.encoding.base8",
"base10": "bases.encoding.base10",
"base16": "bases.encoding.base16",
"base32": "bases.encoding.base32",
"base32hex": "bases.encoding.base32hex",
"base32z": "bases.encoding.base32z",
"base36": "bases.encoding.base36",
"base64": "bases.encoding.base64",
"base64url": "bases.encoding.base64url",
"base10": "bases.encoding.base10",
"base36": "bases.encoding.base36",
"base58btc": "bases.encoding.base58btc",
"base58flickr": "bases.encoding.base58flickr",
"base58ripple": "bases.encoding.base58ripple",
"base45": "bases.encoding.base45"
}
}The special_class_members key can be set to a dictionary, where an entry maps a class's full name to a list of special member names to be explicitly included in the documentation.
The following usage example is adapted from dag-cbor:
"special_class_members": {
"dag_cbor.ipld.IPLDObjPath": ["__new__", "__truediv__", "__rtruediv__", "__le__", "__lt__", "__repr__", "__rshift__"]
}Note. In most cases this key is unnecessary: a special member is included automatically whenever its docstring carries a :meta public: field, as in
def __iter__(self) -> Iterator[Entry]:
"""
Iterates over the entries of this relation.
:meta public:
"""Every special ("dunder") member of the class is considered, so a class can opt any of them into its API page without changes to the generator.
The special_class_members key remains as an escape hatch, for special members which cannot be given a :meta public: docstring: for example, members without a docstring of their own, or members of third-party classes.
The manual_doc key can be set to a dictionary, where an entry maps a member's full name to a list of reStructuredText lines to insert immediately before that member's autodoc directive.
This is useful for members that Autodoc cannot describe on its own, most commonly union type aliases.
The following usage example is adapted from tensorsat:
"manual_doc": {
"tensorsat.diagrams.Block": [
"Type alias for a block in a diagram, which can be either:",
"",
"- a box, as an instance of a subclass of :class:`Box`;",
"- a sub-diagram, as an instance of :class:`Diagram`.",
""
]
}