Documenting Python with autodoc¶
Guidedog documents Python by reading its source. It does not import a package. Docstrings and signatures become part of the document graph. Objects created only at runtime need an explicit description. This is a deliberate boundary.
Setting it up¶
List the extension and tell Guidedog where your packages are, relative to the source
folder, as sys.path tells Python:
extensions = ["sphinx.ext.autodoc"]
autodoc_source_paths = ["../src"]
guidedog migrate writes autodoc_source_paths for you from the lines that
conf.py files use to reach their package, such as
sys.path.insert(0, os.path.abspath('..')). A package installed from elsewhere is
found only if you add the folder that holds it, for example a source checkout of a
dependency; Guidedog never looks in Python’s own site-packages.
The directives then work as in Sphinx:
.. automodule:: shop.cart
:members:
:show-inheritance:
.. autoclass:: shop.Cart
:members: add, remove
:inherited-members:
Every option Sphinx 9.1 accepts is accepted, with the same meaning:
:members:, :undoc-members:, :private-members:, :special-members:,
:inherited-members:, :exclude-members:, :member-order:,
:show-inheritance:, :imported-members:, :ignore-module-all:,
:class-doc-from:, :no-value:, :annotation:, :no-index:,
:no-index-entry:, :synopsis:, :platform:, :deprecated:, and the no-
forms that cancel autodoc_default_options.
Settings¶
These conf.toml settings have Sphinx’s names, values, and defaults.
autodoc_source_paths-
Guidedog’s own: the folders Python modules are found in, in order, relative to the source folder. Only files below them are read, and a path through a symbolic link that leads elsewhere is refused.
autoclass_content-
"class"(default),"init", or"both": which docstrings describe a class. autodoc_class_signature-
"mixed"(default) or"separated", which documents__init__as a method. autodoc_default_options-
A table of options every directive gets, such as
members = trueormember-order = "bysource". A value offalseleaves the option out. autodoc_docstring_signature-
true(default): a first docstring line likename(args) -> resultis the signature. autodoc_inherit_docstrings-
true(default): a member without a docstring takes its base class’s. autodoc_member_order-
"alphabetical"(default),"groupwise", or"bysource". autodoc_preserve_defaults-
false(default): defaults are shown asrepr()would write them;trueshows them as written. autodoc_typehints-
"signature"(default),"description"(as:type:and:rtype:fields),"both", or"none". autodoc_typehints_description_target-
"all"(default),"documented", or"documented_params". autodoc_typehints_format-
"short"(default) or"fully-qualified". autodoc_use_type_comments-
true(default):# type:comments count as annotations. strip_signature_backslash-
Doubles backslashes in signatures, as in Sphinx.
autodoc_mock_imports,autodoc_type_aliases,autodoc_warningiserror-
Accepted. Nothing is imported, so nothing needs mocking; type aliases are not applied.
How Guidedog knows what Python would do¶
Names are followed as Python binds them: from .app import Flask in a package’s
__init__.py makes flask.Flask the class defined in flask/app.py, which
autodoc then shows with :canonical: flask.app.Flask. Base classes are resolved the
same way, their method resolution order is computed as Python computes it, and
inherited members come from the bases’ source. Names imported only under
if TYPE_CHECKING: do not exist when the module runs, so annotations naming them stay
as written, as they do in Sphinx.
Docstrings are the strings Python would store: escapes processed and indentation
removed as Python 3.13’s compiler removes it. Attribute documentation comes from the
places Sphinx’s analyser reads: a #: comment after the assignment or on the lines
above it, and a string literal after it. Signatures come from the def; a class’s
from its metaclass __call__, __new__, or __init__, as Python finds it; a
dataclass’s or NamedTuple’s from its fields; @overload variants replace the
implementation’s signature.
What cannot be known without running Python¶
Guidedog says so, naming the object, whenever the source cannot tell it what Python
would: a warning when something cannot be documented, a note (shown with -v) when
it is documented with less than Sphinx would show.
- A compiled module (
.so,.pyd) has no source to read: its objects are not found. - A value made by running code (
app = Flask(__name__),now = datetime.now()) has no:value:, and a computed default is shown as written. - A function made by a decorator from outside the source paths (
@click.command()) is documented as the function it decorates. - A class from a package outside the source paths is named by the path it was imported from, which may differ from the module that defines it; its members, its constructor’s signature, and the docstrings it would pass on are unknown.
- Docstrings of builtin types are unknown, so a method that has none and would inherit
one from
dictis left out. - Python extensions that handle autodoc’s events (
autodoc-process-docstring,autodoc-skip-member, …) do not run. - A module nested far deeper than real code (Python itself refuses 200 nested brackets;
Guidedog also refuses a
+chain of a few hundred operands) is not analysed, with the warningautodoc.too_deep. - Work that multiplies is bounded: a name followed through imports and aliases stops
after 48 steps along one path and 100,000 in all; a type alias or constant is expanded
for 10,000 steps and is otherwise shown as written; a class’s MRO is followed 100
classes deep; and one directive generates at most 10,000 directives (the warning
autodoc.limit), which only a class that contains itself under its own name reaches.
Adding the missing packages’ source folders to autodoc_source_paths closes most of
these.
Rebuilding¶
Every Python file an autodoc directive read is a dependency of the page: editing it reads the page again on the next build. A page whose object was not found is read again on every build, so it picks the object up as soon as the source has it.
Security¶
Building documentation never runs the project’s code. Guidedog reads Python source as
text, with the same confinement it applies to includes: only below
autodoc_source_paths, and not through links leading elsewhere.