sphinx-autocodelink
Turn the identifiers in your documentation's code blocks into links to the API docs they refer to.
This extension is similar to
sphinx-codeautolink, except it uses
dynamic analysis to resolve links instead of static analysis: it runs your code and asks the
resulting objects what they are, rather than inferring their types from the source. The
dynamic analysis is based on how Sphinx-Gallery resolves
links for its 'reference_url' configuration option.
Running the code is what lets a link land on the right target when the type is written nowhere — a chained call, a subscript, a variable local to a helper function.
Quick start
Install it:
pip install sphinx-autocodelink
Add it to conf.py:
extensions = [
...,
'sphinx_autocodelink',
]
Then point it at the code you want linked. Nothing is linked until you do, so pick whichever row matches where your code already lives:
| Your code is in | Add this |
|---|---|
| Sphinx-Gallery examples | AutoCodeLinkScraper (below) |
| blocks you mark up yourself | .. autocodelink:: (below) |
>>> doctest blocks, anywhere |
autocodelink_doctest_blocks = True |
jupyter-sphinx jupyter-execute cells |
autocodelink_jupyter_blocks = True |
| an extension that already runs code | record_namespace() (below) |
More than one is fine — they can all be on at once.
Sphinx-Gallery
Sphinx-Gallery already runs your example scripts, so this rides along with that. Add
AutoCodeLinkScraper next to your real image scraper(s):
from sphinx_autocodelink.gallery import AutoCodeLinkScraper
sphinx_gallery_conf = {
'image_scrapers': (AutoCodeLinkScraper(), ...), # ... = your other scraper(s), if any
}
That's everything. Examples are linked, parallel=True and all.
The autocodelink directive
Write it wherever you want a block executed and linked. It affects only that block:
.. autocodelink::
import pkg
pkg.thing()
You get a syntax-highlighted, linked code block and nothing else — no figure, no output.
Doctest-style (>>>) content works too, with the prompts stripped before it runs.
Doctest blocks
autocodelink_doctest_blocks = True
Every bare >>> block in your docs — a docstring's Examples section, a hand-written page,
anywhere — is executed and linked, with no markup on any of them.
This one is worth a moment's thought before you switch it on, because it runs code nobody
marked as runnable, including in docstrings autodoc pulls in from your dependencies. A block
that fails is skipped with a build warning rather than failing the build, but it has already
run by then. Each block gets a fresh namespace, so a later block can't see an earlier one's
variables. A statement marked # doctest: +SKIP is not executed — its identifiers still link
when the rest of the block bound their names. executable_script_from_examples() exposes that
same filtering for your own extension (below).
jupyter-execute cells
autocodelink_jupyter_blocks = True
Every jupyter-sphinx .. jupyter-execute:: cell is
executed and linked. The cells already run in a kernel at build time; this runs them a second
time, for a namespace to resolve against. A document's cells share
one namespace, reset at each .. jupyter-kernel::, just like the kernel they mirror — so a
:hide-code: setup cell still resolves the names later cells use. Doctest-style (>>>)
content runs with the prompts stripped, the way the kernel's own IPython accepts it.
A cell that isn't plain Python (an IPython magic, or another kernel language entirely) is
skipped with a warning. A cell that raises still records what ran before the raise, and warns
only when it doesn't declare :raises:.
Your own extension
If your extension already executes code (to render a figure, say), hand the resulting namespace over and skip everything above:
from sphinx_autocodelink import record_namespace
record_namespace(env=env, docname=env.docname, source=code, namespace=ns, state=self.state)
Then call app.setup_extension('sphinx_autocodelink') from your own setup(app).
pyvista's pyvista-plot directive
does exactly this.
Only the top-level namespace of code you execute yourself is resolvable by default. Use
exec_with_local_scopes() in place of exec() to also resolve names that exist only inside
the script's own helper functions:
from sphinx_autocodelink import exec_with_local_scopes
namespace = exec_with_local_scopes(compile(code, filename, 'exec'), {}, filename)
It runs code exactly as exec(code, namespace) would, and returns a namespace with the
script's own calls' locals merged in underneath. Merging is flat, so a local in one call can
shadow a global, or another call's local, of the same name — which resolves to the wrong
link, not to no link.
"Used In" backreferences
.. autocodelink-index:: lists the pages that use each linked name:
.. autocodelink-index::
Pass a documented dotted name for just that one name's references — useful on its own API page:
.. autocodelink-index:: pkg.thing
:label: Used In
:hide-empty:
To get that on every documented object automatically, without writing it anywhere:
autocodelink_autodoc_backrefs = True
This needs sphinx.ext.autodoc loaded, directly or through something that depends on it such
as numpydoc. Without it nothing is appended and no warning is raised. Modules are skipped.
A page is listed only if it actually uses the name — a call, or an attribute read such as a
@property or an enum member. A bare mention (a type hint, an isinstance check) still gets
its own link in the code block, but doesn't earn a "Used In" entry.
A "Used In" entry links to the section holding the code, so it lands on the usage rather than
the top of the page, falling back to a plain page link where there's no one section to point
at. This needs a real, linkable section: numpydoc renders Examples as a .. rubric::, which
carries no anchor, so only projects that turn those rubrics into real headings get the deeper
link.
Categories
Every recording is tagged with where it came from, and the index can group by that tag:
'Sphinx Gallery' for the scraper, 'Docstring Examples' for anything recorded inside an
object's own description, 'Documentation' for everything else. .. autocodelink::,
record_namespace() and AutoCodeLinkScraper all take a category of your own choosing
instead.
Grouping shows a subheading for every category present, even just one. :no-group: renders a
flat list instead.
Categories render alphabetically by their displayed label. Rename the labels, reorder the groups, or both:
autocodelink_category_labels = {'Sphinx Gallery': 'Gallery Examples'}
autocodelink_category_order = ['Docstring Examples', 'Documentation', 'Sphinx Gallery']
autocodelink_category_order lists category strings, not renamed labels, and only the ones
your project actually produces. A category you leave off still renders, alphabetically at the
end, with a build warning naming it.
Configuration
conf.py value |
Default | Does |
|---|---|---|
autocodelink_autodoc_backrefs |
False |
Append a hidden-if-empty "Used In" section to every documented object but modules |
autocodelink_doctest_blocks |
False |
Execute and link every bare >>> block site-wide |
autocodelink_jupyter_blocks |
False |
Execute and link every jupyter-sphinx jupyter-execute cell |
autocodelink_sort |
'alphabetical' |
'frequency' ranks each list by how often the page uses the target |
autocodelink_show_usage_count |
False |
Show each listed page's own count, e.g. Tutorial page (3 uses) |
autocodelink_gallery_cards |
False |
Render gallery entries as thumbnail cards instead of a link list |
autocodelink_category_labels |
{} |
Rename a category's displayed heading |
autocodelink_category_order |
() |
Order the groups explicitly instead of alphabetically |
autocodelink_records_dir |
'_autocodelink_records' |
Where Sphinx-Gallery's worker processes leave their records |
.. autocodelink:: takes :category:. .. autocodelink-index:: takes an optional dotted name
plus :label:, :hide-empty:, :no-group: and :no-titles:.
AutoCodeLinkScraper takes records_dir, category and trace.
Lists longer than 8 entries show the first 5 and tuck the rest behind a "N more" toggle.
autocodelink_gallery_cards = True replaces that with a scrolling carousel of Sphinx-Gallery's
own thumbnails, and needs sphinx-design alongside
Sphinx-Gallery.
Entries are styled to match what they point at, with no configuration: a docstring example
renders like a :class: cross-reference, a gallery example like a :ref:, anything else as a
plain link.
What resolves, and what doesn't
Sphinx-Gallery examples resolve everywhere the example actually ran — including inside its own
helper functions, and through receivers no name can address, like dataset['label_map']. This
needs Python 3.12+; below that, an example resolves from its top-level namespace only.
AutoCodeLinkScraper(trace=False) turns it off. Sphinx-Gallery's reset_modules_order has to
include 'before' (the default), and you get a build warning if it doesn't.
Two things still don't resolve, both because there's nothing executed to observe: a helper the example never calls, and a scope left by a raised exception.
One asymmetry worth knowing: the in-source link on a complex receiver's trailing attribute needs the whole expression on one line. Its "Used In" entry doesn't — that's recorded either way.
If you also set sphinx_gallery_conf['reference_url'] for a module this covers, both extensions
will try to link the same identifiers. Nothing breaks — this one skips anything already inside a
link — but Sphinx-Gallery's own, less precise link wins where both apply. Prefer
intersphinx_mapping, which this reads already and which covers every page, not just gallery
ones.
Code inside a sphinx-design card with a :link: option is skipped the same way.
Development
uv sync --group dev
uv run pytest
uv run pre-commit run --all-files
Metadata
Release files for sphinx-autocodelink 0.11.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sphinx_autocodelink-0.11.3.tar.gz | 80.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sphinx_autocodelink-0.11.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 121.3 kB
Release files / sphinx_autocodelink-0.11.3.tar.gz
| Download URL | sphinx_autocodelink-0.11.3.tar.gz |
|---|---|
| Size | 80.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
659b3b3341851e6352f55ecbfc6a6c2057966fbd3933d46145100913708e3262
|
|
BLAKE2b-256 checksum How to use checksums |
02685c3be7740bc6cafa9b22967713da1e3572a2176b8d37bbeb1a41d670ff88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logRelease files / sphinx_autocodelink-0.11.3-py3-none-any.whl
| Download URL | sphinx_autocodelink-0.11.3-py3-none-any.whl |
|---|---|
| Size | 41.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a2e84e1ca15e2957c30eacf71ddccc686327d7fb871f39f36e91f40d354e5c2d
|
|
BLAKE2b-256 checksum How to use checksums |
3b03ceab6dbaab397d5565c25d82446938bf9f7922953f956664774b930bfadc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency log