sphinx-autodoc-typehints
This Sphinx extension reads your Python type hints and automatically adds type information to your generated documentation -- so you write types once in code and they appear in your docs without duplication.
Features:
- Adds parameter and return types from annotations into docstrings
- Resolves types from
TYPE_CHECKINGblocks and
.pyi stub files
dataclass classes
- Shows default parameter values alongside types
- Types the keys of
**kwargs: Unpack[SomeTypedDict]as keyword arguments - Shows the type parameters of generic classes, functions and type aliases in their signatures
- Shows the message of
@deprecatedobjects as a deprecation notice - Links the base class member an
@overridemethod replaces - Shows the type a property's setter accepts when it differs from the type the getter returns
- Controls union display style (
Union[X, Y]vsX | Y) - Automatically fixes cross-references for stdlib types whose runtime module differs from their documented path
- Supports custom type formatters and module name rewriting
- Extracts descriptions from [
Annotated[T, Doc(...)]](https://typing-extensions.readthedocs.io/en/latest/#Doc)
- Works with Google and NumPy docstring styles
- Reads PEP 484 type comments when a function has no annotations
- Types instance attributes annotated in
__init__for their:ivar:fields
autodoc_typehints
setting (since v2.1) that can move type hints between signatures and descriptions. This extension replaces that with the
features above. See Avoid duplicate types with built-in Sphinx.
- Avoid duplicate types with built-in Sphinx
- Use with Google or NumPy docstring style
- Use with numpydoc
- Control return type display
- Change how union types look
- Show default parameter values
- Document **kwargs typed with a TypedDict
- Document TypedDict classes
- Control overload signature display
- Show deprecations from @deprecated
- Link what an @override method overrides
- Show the type a property setter accepts
- Keep type hints in function signatures
- Handle circular imports
- Resolve types from TYPE_CHECKING blocks
- Show types for attrs or dataclass fields
- Type attributes documented with :ivar: or :cvar:
- Write a custom type formatter
- Document a type alias without expanding it
- Add types for C extensions or packages without annotations
- Use type comments
- Document generators
- List parameters once with autoclass_content = "both"
- Style the injected types
- Fix cross-reference links for stdlib types
- Fix cross-reference links for renamed modules
- Suppress warnings
- Configuration options
- Typing constructs
- Warning categories
- How it works
- How return type options interact
Installation
pip install sphinx-autodoc-typehints
Then add the extension to your conf.py:
extensions = ["sphinx.ext.autodoc", "sphinx_autodoc_typehints"]
It needs Python 3.12 or later and Sphinx 9.1 or later, and it is safe for parallel builds (sphinx-build -j).
Quick start
Instead of writing types in your docstrings, write them as Python type hints. The extension picks them up and adds them to your Sphinx output:
# Before: types repeated in docstrings
def format_unit(value, unit):
"""
Format a value with its unit.
:param float value: a numeric value
:param str unit: the unit (kg, m, etc.)
:rtype: str
"""
return f"{value} {unit}"
After: types only in annotations, docs generated automatically
def format_unit(value: float, unit: str) -> str:
"""
Format a value with its unit.
:param value: a numeric value
:param unit: the unit (kg, m, etc.)
"""
return f"{value} {unit}"
The extension adds the type information to your docs during the Sphinx build. See an example at the pyproject-api docs.
How-to guides
Avoid duplicate types with built-in Sphinx
With Sphinx's own
autodoc_typehints set
to "description" or "both", Sphinx adds the parameters a docstring leaves out with its own plain, unlinked types
(y (str)) next to the ones this extension writes. Set it to "none" to let this extension handle everything:
autodoc_typehints = "none"
Use with Google or NumPy docstring style
If you use sphinx.ext.napoleon for Google-style
or NumPy-style docstrings, load it before this extension:
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"sphinx_autodoc_typehints",
]
Napoleon and this extension share one return type by default: napoleon's :rtype: gives way to the annotation. With
napoleon_use_rtype = False, napoleon puts the docstring's type in the Returns text instead, so set
typehints_use_rtype = False too, or the type shows twice:
napoleon_use_rtype = False # sphinx.ext.napoleon setting
typehints_use_rtype = False
A type written in the docstring's Returns section then stays as written, in place of the annotation's.
See
napoleon_use_rtype
in the Sphinx docs.
With
napoleon_use_param
or napoleon_use_keyword set to False, napoleon lists the parameters, or the keyword arguments, in one field each,
and the types go in parentheses after each name, where napoleon puts a type written in the docstring. A type written in
the docstring is kept. With numpydoc, an Other Parameters section renders this way
too, under its own heading.
The extension supplies the types napoleon would otherwise read from the annotations for parameters and for the
attributes in an Attributes section: a class's, annotated in the class body or where __init__ assigns them, and a
module's, annotated at module level, whether napoleon writes the section as :ivar: fields or, with napoleon_use_ivar
off, as .. attribute:: entries. These render like any other field, linked and with their arguments, while a type
written in the docstring, as in count (int): ..., stays as written. A keyword argument napoleon writes as a
:keyword: field gets a :paramtype: next to it, and a :kwtype: napoleon wrote from the docstring counts as an
existing type.
Use with numpydoc
The numpydoc extension works too; load it before this extension:
extensions = [
"sphinx.ext.autodoc",
"numpydoc",
"sphinx_autodoc_typehints",
]
The Parameters, Other Parameters, Returns, Yields and Raises sections numpydoc produces are turned into field
lists first, so the types from the annotations go in as they do for Sphinx-style docstrings. An entry naming several
parameters, a, b : int, is split into one per name, and a type written in the docstring is kept for a parameter
without an annotation.
Control return type display
By default, return types appear as a separate block in your docs. You can change this:
# Don't show return types at all
typehints_document_rtype = False
Don't show "None" return types, but show all others
typehints_document_rtype_none = False
Show the return type inline with the return description
instead of as a separate block
typehints_use_rtype = False
Change how union types look
A union written with the pipe syntax, str | int, renders that way. Before Python 3.14, a pipe next to a typing
construct, as in Literal["a"] | None or Self | None, builds the same object Optional[...] does, so it renders like
one unless always_use_bars_union is set. One written as Union[str, int] or Optional[str] renders as written by
default; to show those with pipes too:
always_use_bars_union = True
On Python 3.14+, the pipe syntax is always used regardless of this setting.
By default, Optional[Union[A, B]] is simplified to Union[A, B, None]. To keep the Optional wrapper:
simplify_optional_unions = False
With this set to False, a Union[...] or Optional[...] containing None displays as Optional. A union written
with pipes, such as int | str | None, keeps them. The option only matters before Python 3.14, where every union shows
with pipes.
Show default parameter values
To include default values in your docs, set typehints_defaults to one of three styles:
# "param (int, default: 1) -- description"
typehints_defaults = "comma"
"param (int (default: 1)) -- description"
typehints_defaults = "braces"
"param (int) -- description (default: 1)" (at end of text)
typehints_defaults = "braces-after"
None and False leave defaults out, and any other value stops the build with a configuration error. A parameter typed
only in its docstring, by a :type: field, as :param int x: or in napoleon's combined Parameters field, gets the
default next to that type the same way. With "braces-after", the default closes the last plain paragraph of the
description. A list, a directive such as .. note::, or a literal block at the end of the description stays as written,
and a paragraph introducing a literal block keeps its :: last.
A dataclass field declared with field(default_factory=list), or an attrs one with attrs.field(factory=list), gets a
fresh value on each call, and its default reads as that call, list(), in both the signature and the parameter list. An
attrs factory taking the instance reads as make(self). A lambda, or any other factory without a name to look up, keeps
the placeholder, since its source is not reliably recoverable from a generated __init__.
Document **kwargs typed with a TypedDict
PEP 692 types **kwargs key by key through a
TypedDict. The extension types each key documented
as a keyword argument, the way it types a parameter:
class Options(TypedDict, total=False):
verbose: Required[bool]
level: int
def configure(**kwargs: Unpack[Options]) -> None:
"""
Configure the run.
:param kwargs: the options
:keyword verbose: print every step
:keyword level: how much to print
"""
renders verbose as bool and level as NotRequired[int], since a caller may leave it out, and a ReadOnly key
keeps its ReadOnly[...]. A key described through Annotated[..., Doc(...)], or every key with
always_document_param_types = True, gets a keyword entry of its own.
Document TypedDict classes
A TypedDict documented with :members: and :undoc-members: lists its keys as attributes. A key that may be left out
shows as NotRequired[...], also when the class's total=False makes it so rather than its annotation, and one a
caller must pass shows its type alone, also when written as Required[...]. A
PEP 705 read-only key keeps its ReadOnly[...], inside the NotRequired[...] as
the typing spec nests them, so rating: ReadOnly[NotRequired[float]] shows NotRequired[ReadOnly[float]]. The items a
PEP 728 TypedDict accepts beyond its keys show as an Extra items field:
class Counts(TypedDict, extra_items=int):
total: int
shows Extra items: int, and a closed=True class, or one inheriting from it, shows Extra items: Never, its
equivalent. A docstring with its own :Extra items: field keeps it.
Control overload signature display
When a function has @overload signatures, they are
rendered automatically in the docstring, with their types cross-referenced like parameter types and without the self
or cls parameter of a method. Each reads like the overload's signature, with its / and * markers, the stars of
args and *kwargs, and its defaults as written, and an overload taking nothing shows as (). A class lists the
overloads of its __init__ or __new__. To disable this globally:
typehints_document_overloads = False
To disable overloads for a single function while keeping them everywhere else, add :no-overloads: to the docstring:
@overload
def f(x: int) -> str: ...
@overload
def f(x: str) -> bool: ...
def f(x):
""":no-overloads:
f accepts int or str, see docs for details.
"""
The :no-overloads: directive is stripped from the rendered output, also when typehints_document_overloads is off.
The overloads go right after the summary paragraph, so autosummary still picks the summary up. A function documented through its overloads gets no separate return type, since each overload states its own. An exception class lists its constructor overloads like any other class, and a static method keeps its first parameter.
With typehints_use_signature = True the overloads replace the signature instead, one line each, as plain autodoc shows
them, and the Overloads field goes away:
mod.f(x: int) -> str
mod.f(x: str) -> bool
Every line shows its return type, as that is what tells the overloads apart, except for a class, whose lines list its
constructor's parameters. A default an overload writes as ... stays ..., here and in the Overloads field: it says
the parameter is optional, while the implementation's default may be one the overload's type rules out, as True for
flag: Literal[False] = .... Plain autodoc shows the implementation's default instead. Only the first line is the link
target of the object. A signature written in the directive, .. autofunction:: f(x), shows as written, with the
overloads in the Overloads field, while :no-overloads: keeps the signature of the implementation.
Show deprecations from @deprecated
A function, method or class decorated with
@warnings.deprecated (or the
typing_extensions backport) gets a deprecation notice below its summary, styled like Sphinx's
deprecated
directive:
@deprecated("Use fresh() instead.")
def stale(value: int) -> int:
"""Do the stale thing."""
renders Deprecated: Use fresh() instead. The message shows as written, without markup, as it is the text the object
warns with at runtime. A docstring with a .. deprecated:: directive of its own, which can name the version, gets no
second notice, and a subclass of a deprecated class is not marked.
Link what an @override method overrides
A method or property marked with @typing.override
gets an Overrides field that links the member it replaces, found in the nearest base class that defines it:
class Child(Base):
@override
def run(self, count: int) -> str:
"""Run again."""
shows Overrides: Base.run. A method marked @override that no base class defines gets no field. Listed under a
subclass with :inherited-members:, the method still links what it overrides in its own class's bases, and the link
goes through typehints_fixup_module_name like any other.
Show the type a property setter accepts
Autodoc puts the type a property's getter returns in its header, and nothing tells the reader what they may assign. When
the setter's value parameter has a different annotation, the property gets a Setter accepts field with it:
class Box:
@property
def size(self) -> int:
"""The size."""
@size.setter
def size(self, new: int | str) -> None: ...
shows property size: int followed by Setter accepts: int | str. A property without a setter, such as a
functools.cached_property, a setter annotated with the getter's type, or one without an annotation gets no field, and
a docstring with a :Setter accepts: field of its own keeps it.
Keep type hints in function signatures
By default, type hints are removed from function signatures and shown in the parameter list below. To keep them visible in the signature line:
typehints_use_signature = True # show parameter types in signature
typehints_use_signature_return = True # show return type in signature
The kept types read the same as the fields below them: typehints_formatter, typehints_fixup_module_name,
typehints_fully_qualified and documented type aliases apply to both. They are written as Python writes them, so a
NewType shows by its name, UserId rather than the field's UserId (int), a type variable no signature declares
shows as ~module.T, and the markup a formatter returns becomes the name it refers to, so ` :class:bool turns
into bool, which Sphinx then links as it links any annotation.
A function with @overload signatures shows those in
its signature, one line each, in place of the implementation's, see
Control overload signature display.
Handle circular imports
When two modules need to reference each other's types, you'll get circular import errors. Fix this by using
from __future__ import annotations, which makes
all type hints strings that are resolved later:
from __future__ import annotations
import othermodule
def process(item: othermodule.OtherClass) -> None: ...
Resolve types from TYPE_CHECKING blocks
This extension automatically imports types from
TYPE_CHECKING blocks at doc-build time. Any
module-level guard counts, whether it names TYPE_CHECKING directly or through a module alias such as
t.TYPE_CHECKING, including the else branch of if not TYPE_CHECKING: and tests that combine it with and or or.
Annotations read the names as a type checker does, so with else: ArrayLike = Any they document the guarded
ArrayLike. The module itself keeps what it binds at runtime: the fallback, or the function behind @overload stubs,
stays for your code and autodoc during the build, and the block only adds the names the module lacks. When the block
imports a dependency your docs environment lacks, the extension mocks it the way
autodoc_mock_imports
would, so its types still render as cross-references, in a pipe union such as Thing | None too; install it when you
want those references to resolve. That includes a relative import of a sibling module that is absent. An import
statement raises a warning when it fails for another reason, such as a dependency you have installed but that fails to
import. A guarded statement that only a type checker accepts, and that imports nothing, is skipped silently, and the
names it would define still work in annotations. Fix the environment, or suppress the warning:
suppress_warnings = ["sphinx_autodoc_typehints.guarded_import"]
Show types for attrs or dataclass fields
The extension backfills annotations from attrs field metadata automatically. For
dataclasses, annotations are read from the class body. Make sure
the class is documented with .. autoclass:: and both :members: and :undoc-members:, since a field without a
docstring is otherwise skipped.
Type attributes documented with :ivar: or :cvar:
An attribute annotated in the class body, or where __init__ assigns it, gets a :vartype: for its :ivar:, :cvar:
or :var: field:
class Job:
"""
A job.
:ivar retries: how often it ran again
"""
def __init__(self) -> None:
self.retries: int = 0
renders retries as int, as does retries: int in the class body, the way a __slots__ class declares it. A
ClassVar[...] or Final[...] shows the type it holds, and where both declare an attribute the __init__ annotation
wins. Assignments inside if, try and with blocks count, ones in nested functions do not, and an
:ivar int retries: or an existing :vartype retries: stays as written.
Write a custom type formatter
To control exactly how a type appears in your docs, provide a formatter function. It receives the type annotation and
the Sphinx config, and returns RST markup (or
None to use the default rendering):
def my_formatter(annotation, config): if annotation is bool: return ":class:bool" return Nonetypehints_formatter = my_formatter
With typehints_use_signature or typehints_use_signature_return, the formatter also decides the types kept in the
signature, where its markup becomes the name it refers to. A value that is not callable stops the build with a
configuration error.
To always show the full module path for types (e.g., collections.OrderedDict instead of OrderedDict):
typehints_fully_qualified = True
It follows Sphinx's
autodoc_typehints_format
unless set, so autodoc_typehints_format = "fully-qualified" turns it on.
Document a type alias without expanding it
The extension preserves alias names only when they have a .. py:type:: directive in your docs. Without that entry, the
alias is expanded to its underlying type. Add a documentation entry for the alias, and it will render as a clickable
link instead. The entry has to name the alias where the annotation looks it up: .. py:type:: pkg.Vector serves the
functions and methods of pkg, while an alias documented in a submodule such as pkg.compat does not.
A plain assignment such as Count = int evaluates to the very type it names, so without
from __future__ import annotations the extension reads the function's source to tell limit: Count from limit: int.
Only the parameters written with the alias name render as the alias, and functions without source, such as generated
ones, show the underlying type. The extension picks between the alias and its underlying type once every document is
read, so the .. py:type:: entry may come after the function, on its page or in another document, and -j does not
change the result. A signature kept by typehints_use_signature is written while documents are still being read, so it
names the alias only when its entry was read first.
An alias set in
autodoc_type_aliases
renders by its name. It links to the target it names when the docs document that target, as a type, class or data entry;
otherwise the name shows as plain text, so the value may also be a display string. The extension decides once every
document is read, so the result does not depend on the order documents are read in or on -j.
A recursive alias such as type Json = dict[str, Json] | list[Json] | str renders its self-reference as a link to the
alias name. A generic alias used with arguments, Pairs[int], expands with the arguments put in, or shows by name when
the arguments do not fit its parameters.
Add types for C extensions or packages without annotations
The extension reads .pyi stub files
automatically. Place a .pyi file next to the .so/.pyd file (or as __init__.pyi in the package directory) with
the type annotations, and they'll be picked up. Beyond that:
- A function a package re-exports from a native submodule, such as pkg._native.parse
exposed aspkg.parse, takes its
, and a native submodule without a __file__, as PyO3 builds them, finds its
stub too.
- The
@overload variants of a stub combine into a union, unless the stub also gives the implementation's signature.
if sys.version_info and if sys.platform branches are followed for the running interpreter.
A name that exists only in the stub, including a stub TypeAlias or type alias, renders as a cross-reference.
A module the stub imports that isn't installed, import numpy.typing as npt in a docs environment without numpy, is mocked as autodoc_mock_imports would, so npt.NDArray still renders as a cross-reference.
- A C attribute (a getset or member descriptor) gets its type from the stub's
@property or class annotation.
Editing a stub rereads the pages documenting what it describes on the next incremental build.
Looking for a stub reads a package's attributes without running its PEP 562 __getattr__, so a package that imports on first access, or renames what it hands out as anyio does, stays as autodoc
found it.
Use type comments
A function without annotations can carry its types in a
PEP 484 type comment, which the extension reads:
def scale(value, factor):
# type: (float, int) -> float
"""
Scale a value.
:param value: the value
:param factor: the factor
"""
The per-argument form, a
# type: comment after each parameter, works too, and self or cls may be left out of the
comment. A comment that does not parse raises a sphinx_autodoc_typehints.comment warning.
Document generators
A function annotated to return a
Generator, Iterator, AsyncGenerator or AsyncIterator whose docstring has a
Yields section (:Yields:, :yields: or :yield:, as napoleon and numpydoc write it) gets no return type, since the
Yields section already describes what it produces. Its entry gets the yielded type instead,
Yields: int -- the numbers for Iterator[int], unless it states one. Wrapping the annotation in Annotated changes
none of this.
A generator that also hands back a value with
return, Generator[int, None, bool], and documents it in a Returns
section gets that value's type, bool, as its return type; with napoleon, as here:
def count() -> Generator[int, None, bool]:
"""
Yields:
the numbers
Returns:
whether it finished
"""
List parameters once with
autoclass_content = "both"
autoclass_content = "both",
or the :class-doc-from: both option of an autoclass directive, which overrides it for that class, Sphinx shows the
class and the constructor docstrings together. A parameter either of them documents gets its type there, and
always_document_param_types adds the remaining ones only once, under the constructor docstring. So do a Doc()
description, the keys of **kwargs: Unpack[...] and the constructor's overloads, while a @deprecated notice heads the
class docstring.
Style the injected types
Every type the extension adds is wrapped in an inline element with the CSS class
sphinx_autodoc_typehints-type, which
a theme or a custom stylesheet can target.
Fix cross-reference links for stdlib types
Many Python stdlib classes have a
__module__ that points to an internal module rather than their public documented
path. For example, threading.local reports its module as _thread._local, and concurrent.futures.Executor as
concurrent.futures._base.Executor. This produces broken cross-reference links because the extension builds links from
__module__.__qualname__.
When intersphinx is enabled, the extension
automatically fixes this. After intersphinx loads its inventories, it builds a reverse mapping from runtime paths to
documented paths and applies it during annotation formatting. No configuration is needed — just make sure intersphinx is
loaded:
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.intersphinx",
"sphinx_autodoc_typehints",
]
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
}
With this, a type hint like
threading.local correctly links to threading.local in the Python docs instead of
producing a broken _thread._local reference.
Fix cross-reference links for renamed modules
Some third-party libraries expose types under a different module path than where they're documented. For example, GTK
types live at
gi.repository.Gtk.Window in Python, but their docs list them as Gtk.Window. This causes broken
intersphinx links.
Use
typehints_fixup_module_name to rewrite the module path before links are generated:
def fixup_module_name(module: str) -> str:
if module.startswith("gi.repository."):
return module.removeprefix("gi.repository.")
return module
typehints_fixup_module_name = fixup_module_name
Editing the function re-reads the documents on the next incremental build, as changing any other option does. The
extension tells by comparing the function's source, so a change only to a helper it calls or to data it reads goes
unseen; run
sphinx-build -E after such a change. A functools.partial or a callable instance has no source to
compare, so every build re-reads every document; assign a plain function to keep incremental builds incremental.
Suppress warnings
To silence all warnings from this extension:
suppress_warnings = ["sphinx_autodoc_typehints"]
To suppress only specific warning types, see Warning categories for the full list.
Reference
Configuration options
| Option | Default | Description |
| -------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
typehints_document_rtype | True | Show the return type in docs. |
| typehints_document_rtype_none | True | Show return type when it's None. |
| typehints_document_overloads | True | Show @overload signatures in docs. Use :no-overloads: in a docstring for per-function control. |
| typehints_use_rtype | True | Show return type as a separate block. When False, it's inlined with the return description. |
| always_use_bars_union | False | Show Union[X, Y] and Optional[X] with bars too; X \| Y always has them. Always on for Python 3.14+. |
| simplify_optional_unions | True | Flatten Optional[Union[A, B]] to Union[A, B, None]. |
| typehints_defaults | None | Show default values: "comma", "braces", or "braces-after". |
| typehints_use_signature | False | Keep parameter types in the function signature. |
| typehints_use_signature_return | False | Keep the return type in the function signature. |
| typehints_fully_qualified | follows autodoc_typehints_format | Show full module path for types (e.g., module.Class not Class), in signatures too. |
| always_document_param_types | False | Add types even for parameters that don't have a :param: entry in the docstring. |
| typehints_formatter | None | A function (annotation, Config) -> str \| None for custom type rendering. |
| typehints_fixup_module_name | None | A function (str) -> str to rewrite module paths before generating cross-reference links. |
Typing constructs
Some annotations render differently from how they are written:
| Written | Rendered |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
args: Ts, tuple[*Ts] | Unpack[TypeVarTuple(Ts)], tuple[Unpack[TypeVarTuple(Ts)]] |
| args: tuple[int, ...] | Unpack[tuple[int, ...]] |
| def fT: int, class Box(Generic[T]) | T, with the bound in the signature |
| T = TypeVar("T", bound=int) in a non-generic signature | TypeVar(T, bound=int) |
| P.args, P.kwargs for P = ParamSpec("P") | ParamSpecArgs(P), ParamSpecKwargs(P), as written when the signature declares **P |
| UserId = NewType("UserId", int) | UserId (int) |
| Annotated[int, ...] | int, with a Doc(...) in the metadata becoming the description |
| Literal[Color.RED] | Literal[Color.RED], linking the enum member |
| tuple[()] | tuple[()], the empty tuple |
| typing_extensions.Self | Self, linking to typing.Self where typing has it |
| MISSING = sentinel("MISSING") (PEP 661) | MISSING, linking it as module data |
python_display_short_literal_types
on, Literal["a", "b"] renders as 'a' | 'b'.
The table covers the types the extension writes into fields and signatures, and into the header of data, an attribute or
a property autodoc documents, so
count: Annotated[int, ...] shows as count: int there too. A header written by hand,
such as .. py:data:: mod.x with a :type: option, keeps the type as written.
Warning categories
suppress_warnings in
conf.py:
| Category | When it's raised |
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
|
sphinx_autodoc_typehints | Catch-all for every warning from this extension. |
| sphinx_autodoc_typehints.comment | A type comment (# type: ...) couldn't be parsed, or lists fewer types than the function has parameters. |
| sphinx_autodoc_typehints.forward_reference | An annotation names something undefined or isn't valid Python, on 3.14 unevaluated too; shown as written. |
| sphinx_autodoc_typehints.guarded_import | An import in a TYPE_CHECKING block failed for a reason other than an absent dependency. |
| sphinx_autodoc_typehints.local_function | A method of a class defined inside a function can't be processed; wrap wrappers with functools.wraps. |
| sphinx_autodoc_typehints.multiple_ast_nodes | The source of an unannotated function didn't parse to one definition, so its type comment can't be read. |
Explanation
How it works
During the Sphinx build, this extension hooks into two
autodoc events.
First, it strips type annotations from function signatures (so they don't appear twice), unless
typehints_use_signature or typehints_use_signature_return keeps them. Then, it reads the annotations and adds type
information into the docstring -- parameter types go next to each :param: entry, and the return type becomes an
:rtype: entry.
A signature you write yourself is left as written when it names other parameters than the object takes: one in the
directive,
.. autofunction:: mod.f(x, y=3), or on the docstring's first line with
autodoc_docstring_signature.
One with the same parameters, differing only in defaults or types, is replaced by the object's own, and so is one made
of only args and *kwargs, which is what autodoc falls back to when it can't see a class's parameters. A class
takes the parameters autodoc reads for it: those of its metaclass's __call__ ahead of __new__ and __init__, unless
that __call__ only passes args and *kwargs on.
Autodoc writes the type after the name of data, an attribute or a property itself, evaluating the annotation before any
event runs, so a name imported under
TYPE_CHECKING resolved there only when documenting something else had imported it
first. The extension renders that type again once the header is built, the way it renders a field's type, with the type
aliases, typehints_fully_qualified and the TYPE_CHECKING imports applied. The header therefore reads like the field,
not like plain autodoc: RATE: decimal.Decimal shows as RATE: Decimal unless typehints_fully_qualified is on, and a
class from a module in autodoc_mock_imports shows by its name, as it does in a field.
A class whose subscription hands back the class itself, as SQLAlchemy's
TypeEngine does, evaluates TypeEngine[_T] to
a bare TypeEngine. The extension evaluates such an annotation again from its source, keeping the arguments, so the
header, the signature, the parameter, return and :ivar: fields and the overloads all show TypeEngine[_T], with
TypeEngine still linked. The __init__ a dataclass or attrs class generates has no source of its own, so its
parameters take the annotations its fields write. A name the branches of an if annotate differently keeps the bare
class, as the source does not tell which branch ran.
Autodoc leaves the type parameters of a generic object out of its signature. The extension adds them after the name,
with bounds, constraints and defaults, the way PEP 695 writes them:
def firstT: Sized, class Stack[T] and type Pairs[K] = dict[K, K]. A class made generic by subclassing
Generic[T] shows its parameters the same way. A type parameter a signature declares this way renders by name where it
is used, as items (T) or args (P.args), while a type variable no signature declares keeps its full
TypeVar(T, bound=int) form. An overload declaring its own, def getS: str -> list[S], renders them by
name in its entry of the Overloads field. A signature written by hand, such as .. py:function:: first(items), shows
only the type parameters it writes.
A member inherited from a generic base and documented under a subclass that binds the base's type parameters, as
:inherited-members: lists it or .. automethod:: mod.Child.get names it, shows the arguments the subclass gives them.
With class Child(Base[int]), Base.get(self) -> T documents as returning int under Child, while Base.get keeps
T. The binding follows the bases through every level, so class B(A[list[U]]) and class C(B[int]) turn A's T
into list[int] under C, and it covers the parameters and return type of methods and of the constructor a class
documents, the overloads of either, the header of an attribute or property, so value: T reads value: int under
Child, and the :vartype: a class-body annotation gives an :ivar:. A TypedDict binds the same way:
class IntOptions(Options[int]) shows the keys it inherits with int, as does **kwargs: Unpack[Options[int]]. A type
parameter the subclass leaves unbound, class Child(Base), stays as it is, and one it passes on,
class ChildU, renders by name as a parameter the subclass declares.
Only parameters that already have a
:param: line in the docstring get type information added, with two exceptions: a
parameter whose annotation carries a Doc(...) description gets a :param: line of its own, and the entries of
napoleon's combined parameter field get their types in place. Set always_document_param_types = True to add types for
all parameters, even undocumented ones; the added lines follow the signature's order, next to the documented parameters,
and go into napoleon's combined Parameters or Keyword Arguments field when the docstring lists the others there.
Parameters are recognized under
:param, :parameter, :arg, :argument, :keyword, :kwarg and :kwparam, naming
args and kwargs bare or with escaped stars, args or \args. Only fields that start a line count: one indented
into a literal block, a code block or a directive such as a note is left as written. A type written in the field,
:param int x:, and a :type x: field give way to the annotation, and a parameter without one keeps its docstring
type. A @typing.no_type_check function still gets its types, decorated functions are documented through __wrapped__,
a class or function stating its signature in __signature__, as a pydantic model does, through that signature, a
functools.partial or partialmethod through the function it calls with the bound arguments left out, a callable
instance documented as a function or method through its __call__, a data or attribute entry holding a callable gets no
parameter or return types since it documents a value, and an annotation that fails to evaluate shows as written,
whatever its own code raises, with a warning only when it names something undefined or isn't valid Python.
How return type options interact
The return type options combine as follows:
- Both defaults (
typehints_document_rtype = True, typehints_use_rtype = True) -- return type appears as a separate :rtype: block below the description.
- Inline mode (
typehints_document_rtype = True, typehints_use_rtype = False) -- return type is appended to the :return: text. If there's no :return: entry, it falls back to a separate block. A :return: entry that already
states its type, such as napoleon's int -- the value, is left as it is, while a description that only contains a
--, such as the value -- or None when missing, still gets the type. Next to an :rtype: field, which the
annotation replaces, the :return: text always counts as a description.
- Disabled (
typehints_document_rtype = False) -- no return type is added from the annotation, regardless of other settings; an :rtype: written in the docstring stays as written.
- Skip None (
typehints_document_rtype_none = False) -- hides None return types specifically, other return types still appear. Annotated[None, Doc(...)] loses its type too, but keeps its description.
Classes and constructors get no return type, and a property shows its type in its header instead. An
:rtype: written
in the docstring, over one line or several, gives way to the annotation. The separate block goes after the parameter
fields, before the first directive or other block that follows them, or at the end. A return annotation carrying a
Doc(...) description adds a :return:` entry when the docstring has none.